TiDB 内核解剖室SECTION 07

一次真实 ADD INDEX 的 4.09 秒 —— 官方说「一般操作中看不到」的中间状态,我们每 10ms 采一次,全抓下来了

1024 TiDB AIGC 黑客松 · 参赛作品 v0.2
absent delete only write only write reorganization public 官方口径的状态流:absent → delete only → write only → write reorg → public 蓝色 = 当前所在状态 · 绿色 = 已走过的状态 · 本页回放驱动
0.0 ms4,085.7 ms
t—
state—
schema_state—
row_count—
正在取回采样数据……
这张表上跑的是 80 万行数据的 ADD INDEX。官方口径说「中间状态转换很快,一般操作中看不到」—— 我们用一条独立连接每 10ms 轮询一次 information_schema.ddl_jobs,在 4,085.7 ms 里采到 179 个采样点。 看进度轨上的 7 个刻度:前 3 个状态转换点全部挤在起点 5% 内,收尾的 row_count 到位挤在终点 —— 中间 3.7 秒(91% 时长)整个属于 write reorganization 回填。这就是「转换很快」在时间轴上的真实样子。
E1 · 关键帧表 —— 采样序列压缩后(状态/相位变化点 + row_count 每 10% 一个点)
#t (ms)stateschema_staterow_count
1159.8queueingnone0
2191.4runningdelete only0
3217.9runningwrite reorganization0
43950.8runningwrite reorganization800,039
54033.8runningwrite reorganization800,278
64056.3donepublic800,278
74079.1donepublic800,278
ROW_COUNT 的全量序列在 3.7 秒回填期几乎不动(0 → 0 → 0 → 800,039 → 800,278), 收尾一次性到位 —— 这是轮询在真机上观察到的行为,原样回放,不做平滑修饰。完整 179 个采样点存于 dev/probe/ddl_timeline.json,可下载逐条复核。

E2在线性 —— 回填期间业务写入零失败

253 / 253
并发写入成功 / 尝试 · 0 失败
p50
4.72 ms
p95
7.48 ms
max
17.71 ms

一条独立连接与回填同时跑满全程:每约 10ms 一条 INSERT,不阻塞其他会话中的 DML —— 官方口径在这里变成了 253 个真实返回。

E3并发规则 —— 同表互斥 vs 不同表并行

同表lab.ddl_same:A 完成 3,608 ms | B 总耗时 6,780 ms(其中等待 ≈ 3,172 ms —— B 被 A 挡住) 不同表lab.ddl_a / lab.ddl_b:2,449 ms | 2,454 ms(发出后 400ms 快照:两条同时 running · write reorganization)

官方从 v6.2.0 起的判定规则是「涉及同一张表的 DDL 相互阻塞」「涉及不同表的加索引和列类型变更可以并发执行」—— 上面两组数字就是这两句话各自的一次实测。

E4失败路径 —— 回填到一半强行取消

  1. 267 msrunning · write only
  2. 332 msrunning · write reorganization
  3. 626 mscancelling · write reorganization ← ADMIN CANCEL 生效
  4. 3718 msrollback done · schema_state 回到 none
ALTER 侧收到:ERROR 8214 (HY000): Cancelled DDL job
取消返回:('180', 'successful')

取消时该 job 的 COMMENTS = ingest, DXF —— 说明它确实死在真实的加速回填过程中,而不是排队阶段。这条路径与官方错误原文逐字一致。

E1+完成后的 job 行长什么样

JOB_ID163 (add index · lab.ddl_demo) STATEsynced | SCHEMA_STATE public ROW_COUNT800,278 COMMENTSingest, DXF, max_node_count=3 执行窗口09:31:26.604 → 09:31:30.554(v8.5.7)

这一行是 ADMIN SHOW DDL JOBS 的原始输出(未改字段)。COMMENTS 里的 ingest / DXF 即「走了 fast-reorg 加速回填 + 分布式执行框架调度」的直接证据。

为什么这页值得看:把「看不到」变成「看得到」不是动画技巧,而是采样密度问题。本页没有任何示意值: 每个数字都来自一次真实采集(2026-09-21 09:31,v8.5.7 三节点集群,80 万行表),回放是对采样序列的忠实重放 —— 连 row_count 的跳变方式都原样保留。原始产物就在 dev/probe/ddl_timeline.json 与 dev/probe/ddl.txt, 采集脚本 dev/ddl-sample.py 四个实验的参数全部写死,可原样复跑。
  • 边界一:轮询不是事件监听 —— 两次采样之间发生的状态跳变看不见(比如 delete only 只被采到 1 次,write only 在 E1 中完全没采到)。我们抓到的 7 个关键帧,仍然是真实序列的下界。
  • 边界二:这是 3 节点实验集群,4.09 秒不是生产基准 —— 数字的意义在机制,不在快慢。
  • 边界三:采集时刻的所有相关系统变量(fast_reorg / dist_task / worker_cnt / batch_size)见右侧环境卡 —— 换一组参数,时长与路径都会变。
本轮采集环境
版本TiDB v8.5.7(8.0.11-TiDB-v8.5.7) 集群3 节点 · 192.168.3.110 / .112 / .114 fast_reorg1(加速索引回填) dist_task1(分布式执行框架) worker_cnt4(轻负载档) batch_size256(轻负载档) DDL Owner192.168.3.110:4000(与接入节点一致)
采集方法(可复跑)
脚本dev/ddl-sample.py 实验E1 状态机 · E2 在线写入 · E3 并发 · E4 取消 采样独立连接 · 10ms 轮询 ddl_jobs 产物dev/probe/ddl_timeline.json(179 点)· ddl.txt
诚实边界
① 10ms 轮询存在盲区:两次采样之间的跳变不可见(write only 在 E1 中未被采到 —— 它比一轮轮询还快)。 ② row_count 在 fast-reorg 回填期不渐进刷新,收尾一次性到位;这是观察事实,不代表回填「最后才做」。 ③ 3 节点实验集群,非生产规模;请把它当作机制证据,而不是性能基线。
怎么核验这页
带虚线下划线的数字都可以点开 —— 每张取证卡给出对应官方文档与原文引用。 原始数据与日志在 dev/probe/ 下,与页面数字逐条可对。