0. 数据量评估与策略选择
- 估算数据量:通过
COUNT或抽样估算待处理记录数。 - 分级策略:
- 小数据量(< 1000条):可在线修改,备份受影响行即可。
- 中数据量(1000 ~ 10万条):全表备份,脚本分批处理。
- 大数据量(> 10万条):必须全表备份,采用离线脚本 + 分页/分区处理,避开高峰期。
1. 备份(安全第一)
- 全表备份:
CREATE TABLE table_bak_YYYYMMDD AS SELECT * FROM table; - 增量备份:仅备份待处理主键集合:
CREATE TABLE table_keys_bak AS SELECT id FROM table WHERE condition; - 备份验证:确认备份记录数与预期一致,索引完整。
2. 单条处理与验证(测试环境)
- 构造典型样本:覆盖正常、边界、异常数据(至少3~5条)。
- 手动或脚本单条执行:观察结果是否符合预期。
- 验证维度:
- 业务逻辑正确性
- 关联表数据一致性
- 无副作用(如触发器、外键约束)
- 记录验证日志:输出处理前后的数据快照。
3. 批量处理脚本开发要点
3.1 可重复执行(幂等性)
- 使用
WHERE processed_flag = 0或记录处理状态字段。 - 或基于主键范围:
WHERE id > last_processed_id。 - 事务控制:每 N 条提交一次,避免长事务锁表。
3.2 分页 / 分批处理
- 推荐方式:使用
LIMIT offset, batch_size(注意大 offset 性能差,改用WHERE id > cursor)。 - 批次大小:根据单条处理耗时和数据库负载设置,通常 500~2000 条/批。
- 内存控制:每次只加载一批数据到内存,处理完立即释放。
3.3 进度可视化
- 控制台输出:
[2025-06-01 10:00:01] 已处理 1200 / 100000 (1.2%),预计剩余 3分20秒 - 记录进度表:创建
batch_process_log表,记录批次号、已处理行数、状态、错误信息。 - 支持断点续传:重启脚本时从上次中断点继续。
3.4 异常处理与重试
- 单条失败不终止整体:捕获异常,记录失败 ID 到错误表,继续下一条。
- 提供重试机制:单独脚本处理错误表中的记录。
3.5 性能优化
- 批量 SQL 代替循环单条:如
UPDATE ... WHERE id IN (...) - 关闭自动提交,批量提交事务。
- 暂时禁用索引、触发器等(谨慎评估后操作)。
4. 执行前演练
- 先在预发布环境执行完整流程(备份→单条→批量→验证)。
- 对比执行时间,估算生产环境窗口。
- 准备回滚脚本:
INSERT INTO table SELECT * FROM table_bak WHERE id IN (...);
5. 生产批量执行
- 选择低峰期,通知相关团队。
- 实时监控:数据库 CPU/IO、锁等待、慢查询。
- 记录详细日志:开始/结束时间、处理总数、成功数、失败数、失败详情。
6. 抽样验证与全量确认
- 分层抽样:按主键模 100、或随机抽取 1% 记录,逐一核对。
- 业务验收:让业务方验证关键数据指标(如总金额、状态分布)。
- 对比备份表:
SELECT COUNT(*) FROM table t LEFT JOIN table_bak b ON t.id=b.id WHERE t.field != b.field; - 观察一段时间:确认无下游异常告警。
7. 收尾工作
- 清理备份表(保留 7~30 天,或移至归档库)。
- 记录处理报告:包含处理时间、数据量、异常情况、验证结论。
- 更新文档:将此次处理逻辑固化到运维手册。
补充:常见坑点与避坑指南
| 坑点 | 解决方法 |
|---|---|
大批量 UPDATE 锁全表 |
使用 WHERE 分批 + 合理索引,或采用 pt-online-schema-change |
| 内存溢出(PHP) | 使用 yield 或游标查询,不要一次性 fetchAll |
| 主从延迟导致备份不一致 | 在从库执行备份,或使用可重复读隔离级别 |
| 脚本执行中超时断开 | 设置 set_time_limit(0),配合 nohup 或消息队列 |
| 未考虑外键约束导致失败 | 临时禁用外键检查(谨慎),或按依赖顺序处理 |