Seconds_Behind_Master显示0不代表健康,可能SQL线程正卡在超大事务中不动,而Relay_Log_Space已暴涨至6GB+;必须拆分事务并同步启用LOGICAL_CLOCK并行复制、合理设置workers数及commit_order保护。

不停机迁移时遇到超大事务,不是“能不能扛住”的问题,而是“必须拆掉,否则迁移必然失败”。Seconds_Behind_Master 显示为 0 不代表健康,它可能正卡在一条 UPDATE 上一动不动,Relay_Log_Space 却已暴涨到 6GB+——这是 SQL 线程彻底堵死的铁证。
为什么超大事务会让迁移窗口直接失效
迁移过程依赖主从实时同步,而超大事务(如 UPDATE t SET status=1 WHERE created_at 影响 300 万行)会强制让 SQL Thread 完整执行完才更新 Relay_Log_Pos 和 Seconds_Behind_Master。这期间:
- 所有后续 binlog 排队等待,新写入的数据在从库不可见,流量切换后立刻丢数据
- 即使开了
slave_parallel_workers = 16,WRITESET 并行也对单事务内部无感,仍退化为单线程回放 -
SHOW SLAVE STATUS显示Slave_SQL_Running: Yes,但Slave_SQL_Running_State长期卡在Updating main table - pt-heartbeat 监控会暴露真实延迟:端到端差值可能已达数分钟,远超迁移容忍阈值
安全拆分 UPDATE/DELETE 的唯一可靠方式
别碰 LIMIT + ORDER BY created_at——字段没索引、并发插入导致排序漂移、跳过间隙后无法判断是否结束。真正可落地的只有主键切片:
- 先查边界:
SELECT MIN(id), MAX(id) FROM t WHERE status = 0 AND created_at - 按固定步长构造区间:
WHERE id BETWEEN 100000 AND 109999 AND status = 0 AND created_at (确保条件完全复用) - 每次执行后检查
ROW_COUNT():为 0 就立即退出循环,避免空跑消耗连接和锁 - 每批必须显式
COMMIT,禁用autocommit;不能包在同一个事务里 - 目标表必须有
id主键或唯一索引,且 WHERE 条件能命中该索引(用EXPLAIN确认)
拆分脚本必须支持断点续跑
迁移窗口内网络抖动、从库临时负载高、某批语句锁等待超时,都可能导致中断。没断点逻辑 = 主动埋雷:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 每次成功执行后,把最后处理的
id写进一张专用表(如meta_migration_checkpoint),字段为last_handled_id BIGINT UNSIGNED - 下次启动先查该值:
SELECT last_handled_id FROM meta_migration_checkpoint WHERE task = 't_status_update',然后从WHERE id > ?继续 - 每批操作加
timeout(如SET lock_wait_timeout = 5)和重试(最多 2 次),失败就记录日志并退出,不阻塞后续批次 - 禁止用
OFFSET分页,它随数据变化而偏移,漏数据风险极高
配套参数不调,拆了也白拆
只拆事务不改复制参数,小事务照样串行回放,延迟照旧。以下三项必须同步生效:
-
slave_parallel_type = LOGICAL_CLOCK(MySQL 5.7.22+ / 8.0 必须,DATABASE类型对单库无效) -
slave_parallel_workers = 4~8(设太高反而增加调度开销,别盲目堆到 16+) -
slave_preserve_commit_order = ON(必须开启,否则主从一致性无法保障)
主库还需确认已启用组提交:binlog_group_commit_sync_delay 建议设为 100000~200000 微秒,否则从库并行效果打折。










