最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何修复MySQL主从复制中因大事务导致的秒级延迟?
时间:2026-08-08 09:29:55 编辑:袖梨 来源:一聚教程网
大事务导致主从延迟是因为SQL线程必须等整个事务执行完才更新Seconds_Behind_Master;拆分INSERT INTO SELECT需按主键分段、每批5k–10k行、独立提交、目标表建索引,并避免依赖实时MAX(id)。
大事务是主从延迟最顽固的成因,必须拆分,不能只调参或升硬件。
为什么 INSERT INTO ... SELECT 会让从库卡住几十秒?
MySQL 的 SQL 线程回放事务时,必须等整个事务执行完才更新 Seconds_Behind_Master。一个未拆分的 INSERT INTO dst SELECT * FROM src 执行 25 秒,从库在这 25 秒内:- 不会推进复制位点- 主库新产生的 binlog 全部排队等待- Seconds_Behind_Master 可能一直显示为 0 或旧值,监控完全失灵
如何安全拆分 INSERT INTO ... SELECT?
不能用 LIMIT + OFFSET,会漏数据;也不能只加时间条件,源表可能正在写入。正确做法是:-
- 按主键(最好是自增
id)分段,例如WHERE id BETWEEN 100000 AND 200000,确保范围不重叠、可覆盖全量 - 每批控制在 5k–10k 行以内(单行越宽,批次越小;目标是单次执行 ≤ 2 秒)
- 每批用独立事务提交,避免长事务锁表
- 目标表必须有对应索引,否则
INSERT本身就会变慢,拆分反而更差 - 可选加
SLEEP(0.1)缓冲,降低从库瞬时压力
UPDATE / DELETE 大表时怎么避免锁表+延迟?
这类操作若没走索引或没加 LIMIT,会在从库长时间持有锁,阻塞其他事务回放:-
- 先用
EXPLAIN确认 WHERE 条件是否命中索引;没命中就加索引,别硬扛 - 改写为带
LIMIT的循环:例如UPDATE t SET status=1 WHERE status=0 ORDER BY id LIMIT 5000,查ROW_COUNT()判断是否结束 - 禁用
binlog_format = STATEMENT下的大范围 DML,它在从库可能因函数、临时表等执行失败或更慢 - 避开读流量高峰期执行,尤其不要在从库承担报表查询时跑批量任务
最容易被忽略的一点:拆分逻辑必须覆盖所有数据,且不能依赖 MAX(id) 实时值——如果源表持续写入,MAX(id) 会漂移。应先查出最大 id 快照,或用双游标方式处理活跃写入场景。