从库加索引比主库加更关键,因为从库单线程回放binlog时,若缺索引会导致WHERE条件全表扫描,每条语句延迟累加,而主库索引对从库回放无影响。

直接结论:从库缺索引导致的主备延迟,必须在从库停复制、加索引、再启复制,不能只在主库加——主库加了索引不影响从库回放效率。
为什么从库加索引比主库加更关键
主库执行 UPDATE 或 DELETE 时走索引,只是让它自己快;但从库是单线程回放 binlog,每条语句都得重新定位数据行。如果从库表上没索引,WHERE orderid = '77585' 这种语句就会触发全表扫描,1 条耗 1 秒,50 条就拖出 50 秒延迟。主库有没有索引,完全不影响从库这一步。
常见错误现象:
-
SHOW PROCESSLIST在从库看到大量Updating状态,且Time持续增长 -
EXPLAIN对应的WHERE字段显示type: ALL(全表扫描) -
Seconds_Behind_Master随着某类语句批量出现而阶梯式上涨
如何快速定位哪张表、哪个字段缺索引
先确认延迟是否真由慢回放引起:
在从库执行:SHOW SLAVE STATUS\G,看 Seconds_Behind_Master 和 SQL_Delay;再执行:PAGER grep -v Sleep; SHOW PROCESSLIST,观察正在执行的 SQL 是否集中于某张表的 UPDATE/DELETE。
接着抓一条典型语句做分析:
- 用
mysqlbinlog --base64-output=decode-rows -v /path/to/relay-log.000xxx | grep -A 10 -B 2 "UPDATE.*SET"找出实际回放的语句 - 对语句中的
WHERE条件字段,在从库执行:EXPLAIN SELECT * FROM db.table WHERE field = 'xxx' - 若
key列为NULL、rows接近表总行数,基本可断定缺索引
在从库加索引的安全操作流程
不能直接 ALTER TABLE——MySQL 5.6+ 虽支持 Online DDL,但 ADD INDEX 在从库仍可能阻塞 SQL 线程,导致延迟进一步扩大。
正确做法是主动暂停回放,再加索引:
- 在从库执行:
STOP SLAVE; - 确认已停:
SHOW SLAVE STATUS\G中Slave_SQL_Running: No - 加索引(注意加前先设
SET sql_log_bin = 0;,避免该 DDL 再写入 binlog 反向同步到主库):ALTER TABLE db.table ADD INDEX idx_field (field); - 加完后执行:
START SLAVE; - 立即检查:
SHOW SLAVE STATUS\G中Seconds_Behind_Master是否开始下降、Relay_Log_Pos是否持续前进
注意:slave_rows_search_algorithms='TABLE_SCAN,INDEX_SCAN,HASH_SCAN' 这个参数仅在 ROW 格式下起作用,且无法替代真实索引——它只是让从库尝试用哈希或索引加速查找,但没索引时仍 fallback 到全表扫描。
容易被忽略的两个细节
一是表无主键却有普通索引,照样会慢:MySQL 在 ROW 复制下,若表无主键或唯一非空索引,binlog 会记录所有匹配行的完整镜像,从库回放时仍需逐行比对,INDEX_SCAN 失效,最终退化成 TABLE_SCAN。
二是索引字段区分度低(比如 status TINYINT),即使加了索引,WHERE status = 1 仍可能扫大量行——这时得结合业务判断是否需要组合索引,或改用覆盖索引减少回表。


















