按主键范围分批处理可避免锁表、日志暴涨和主从延迟;最直接方式是按自增ID切片,如将大DELETE语句拆分为多个小范围主键条件执行。

按主键范围分批处理
大事务常因一次性更新或删除大量数据导致锁表、日志暴涨、主从延迟。最直接的拆分方式是按主键(尤其是自增ID)切片。例如原语句:
DELETE FROM orders WHERE create_time
可改写为循环执行:
- 先查出最小和最大ID:SELECT MIN(id), MAX(id) FROM orders WHERE create_time
- 每次删5000行:DELETE FROM orders WHERE id BETWEEN ? AND ? AND create_time
- 每次执行后加休眠(如100ms),降低对线上影响
用游标或时间窗口滚动推进
对无法依赖主键的表(如无合适索引、或主键不连续),可用时间字段+游标方式。关键点是确保每次查询能走索引,且范围可控:
- 首次取最早时间点:SELECT MIN(create_time) FROM logs WHERE status = 'pending';
- 后续每次处理1小时窗口:UPDATE logs SET status = 'done' WHERE create_time >= '2023-01-01 10:00:00' AND create_time
- 记录最后处理的时间点,作为下一轮起点,避免漏数据或重复处理
业务层配合:异步化 + 状态机
数据库只是执行单元,真正防长事务要从应用逻辑入手。把“一气呵成”的操作拆成可中断、可重试的状态流转:
- 将“导入10万条数据并校验+计费+通知”拆为:导入→校验中→校验完成→计费中→计费完成→通知中
- 每步只做一件事,失败时停在当前状态,后台任务轮询继续,不占用长连接
- 用户看到的是“处理中”,实际数据库里每个SQL都是秒级小事务
监控与熔断兜底
再好的拆分也可能遇异常(如某批次卡住、索引失效)。需主动防御:
- 设置单次事务超时(MySQL innodb_lock_wait_timeout 建议调低至10–30秒)
- 应用层统计执行耗时,单次超过5秒自动放弃并告警
- DBA侧配置长事务告警(如information_schema.INNODB_TRX中trx_started早于30分钟的事务)










