大表加索引导致从库延迟是因SQL线程串行回放DDL阻塞所致,主库INPLACE加索引快而从库仍走全量流程,硬件弱或未调优时更慢2–5倍;可通过STOP SLAVE、pt-online-schema-change或复制过滤规避。

大表加索引本身不直接写入 binlog,但会触发从库 SQL 线程执行 ALTER TABLE 语句,而该操作在从库是单线程串行回放的——只要它耗时长,就会卡住后续所有事务,延迟秒数(Seconds_Behind_Master)立刻跳升。这不是“慢查询”问题,而是“阻塞型 DDL”问题。
为什么从库加索引比主库更慢?
主库执行 ALTER TABLE ... ADD INDEX 时,若使用 ALGORITHM=INPLACE,实际只修改元数据+构建 B+ 树,不锁全表;但从库回放该 DDL 时,MySQL 不区分执行上下文,仍按完整 DDL 流程走:读取表数据、构建索引、写入磁盘。尤其当从库硬件弱(如机械盘、buffer pool 小)、或未调优时,这个过程可能比主库慢 2–5 倍。
- 从库默认
read_only=ON,但索引构建仍需大量磁盘随机写 + buffer pool 缓存压力 - 主库可能已预热数据页,从库冷启动,首次读取全表扫描极慢
- 从库若同时承担读流量,
SELECT与 DDL 竞争 I/O 和 CPU 资源
如何判断是索引操作引发的延迟?
执行 SHOW SLAVE STATUS\G 后重点关注三组值:
-
Seconds_Behind_Master突然跳到几百/上千秒,且持续不降 -
Exec_Master_Log_Pos几乎不动,而Read_Master_Log_Pos正常增长 → 说明 IO 线程正常拉日志,SQL 线程卡在某条 DDL 上 -
Slave_SQL_Running_State显示altering table或copy to tmp table(即使主库用了 INPLACE,从库也可能退化为 copy)
此时再查 SHOW PROCESSLIST,能看到 State: altering table 的线程正在跑,基本坐实。
规避策略:不让从库真正“执行”加索引
核心思路是:把索引创建动作从复制流中剥离,让从库跳过该 DDL,改由人工同步或工具辅助完成。
- 主库执行前先停复制:
STOP SLAVE;,然后加索引,再START SLAVE;—— 仅适用于可接受短时延迟的场景 - 用
pt-online-schema-change工具:它在主库以无锁方式建影子表+同步数据,最终RENAME切换;而RENAME是轻量操作,从库回放快,几乎不延迟 - 设置复制过滤:
replicate_ignore_db或replicate_wild_ignore_table,临时跳过该库/表的 DDL(需评估业务影响) - 升级到 MySQL 8.0+ 并启用
slave_ddl_exec_mode=IDEMPOTENT:允许重复执行 DDL 而不报错,便于事后手动补索引(但不解决延迟本身)
从库参数层面缓解 DDL 压力
如果必须让从库自己回放 DDL,至少避免因配置放大延迟:
- 增大
innodb_buffer_pool_size(建议设为主库的 70–80%),减少磁盘扫描次数 - 调高
innodb_io_capacity和innodb_io_capacity_max(SSD 场景设为 2000/4000) - 关闭
innodb_stats_on_metadata=OFF,防止索引构建时额外采样开销 - 避免在从库执行
mysqldump或xtrabackup:它们会触发FLUSH TABLES WITH READ LOCK,直接卡死 SQL 线程
真正难处理的不是“怎么加索引”,而是“加索引这件事是否必须走复制链路”。很多团队踩坑后才发现:主库加完,手动在从库 CREATE INDEX 并校验一致性,反而比等复制更快、更可控。


















