已采纳
回答正文
回复
讨论正文
该问题的正文与回答。
【背景】
我负责一张 MySQL 8.0.32 / InnoDB 的结算流水表 t_settlement,约 1.2 亿行、单表约 60GB,PK=id,现有 4 个二级索引。近两个月每天约 35% 的行被批量 UPDATE status,观察到按 idx_merchant_time 点查的 P99 从 9ms 慢爬到 40ms,SHOW TABLE STATUS 的 Data_free 从 0 涨到 1.8GB——基本可以判定是二级索引页分裂 + 碎片把 B+ 树"撑胖"了。我想在线重建这套索引(DROP+ADD 或等价手段),业务要求全程不锁写、对 P99 影响可控、可回滚。
【现象 / 卡点】 选工具方向社区已讨论很多(我读了《给 2.4 亿行大表加索引:Online DDL 三种姿势的锁窗口实测与工具取舍》和那条"5 亿行核心表 pt-osc / gh-ost / 原生怎么选"的提问,方向我基本认可用 gh-ost)。但真正卡住我的是执行细节,不是选型:
RENAME 切主表,这一瞬间会拿 MDL / 表级锁。在 2000+ DML QPS 的表上,这个锁窗口我没法预估——有没有办法在切换前把锁窗口量化到可接受范围(比如靠 chunk 追平程度、max-lag-millis 余量、--assume-rbr / 心跳表延迟来判断"此刻切表锁会持有多久")?chunk-size 和 max-lag-millis 我目前只能拍脑袋。想问:在"读 QPS 8000 / 写 QPS 2000、主从延迟平时 0.3~1s"这种负载下,你们的经验值区间是多少?chunk 设小了追平慢、设大了单 chunk 事务大,这个 trade-off 你们怎么定?【已尝试与结果】
gh-ost,全程约 26 分钟,切表那一瞬客户端没有报错,但我没法观测到锁实际持有了多久(performance_schema.metadata_locks 采样 1s 没抓到切换瞬间)。ALTER TABLE ... DROP INDEX, ADD INDEX 走 INPLACE,但担心重建期间 undo / redo 压力和长事务阻塞,没敢上。【期望得到的答案形态】
chunk-size / max-lag-millis 在高并发 DML 下的取值依据,而不是纯经验值;performance_schema 或 sys 库的具体观测 SQL。(说明:本表不涉及改字段类型,纯"重建索引/收碎片"场景,所以 INSTANT 不适用,这点我清楚。)