归档前须确认表含合适时间字段并已索引,如created_at;无时间字段时慎用自增id替代;通过show create table和select min/max验证字段有效性;再用delete + limit分批删除。

归档前先确认表是否有合适的时间字段
没有时间维度的表几乎无法做自动化归档,created_at、updated_at、log_time 这类字段必须存在且被索引。如果只有自增 id,而业务上又明确“老数据”指“ID 小于某值”,那可以临时用 id 替代,但要注意:自增 ID 不等于时间顺序(比如批量回填、主从延迟、replace into 等场景会导致 ID 乱序)。
检查方式:
SHOW CREATE TABLE order_log;看字段定义和索引;执行
SELECT MIN(created_at), MAX(created_at) FROM order_log;确认时间范围是否连续、有无空值。
用 DELETE + LIMIT 分批删除老数据
直接 DELETE FROM order_log WHERE created_at 在大表上会锁表、打满 binlog、拖慢主库。必须分批删:
- 每次只删 5000–10000 行,用
WHERE created_at (注意加 <code>ORDER BY避免重复或遗漏) - 两次删除之间加
SLEEP(0.1)(在存储过程中用DO SLEEP(0.1)),缓解 I/O 和复制压力 - 删除后立刻
ANALYZE TABLE order_log,避免优化器因统计信息滞后选错执行计划 - 务必在低峰期执行,且提前在从库验证语句执行耗时
归档到历史库要用 INSERT … SELECT + 建好目标表结构
不要用 mysqldump 导出再导入——太慢、不可控、难断点续传。优先走 SQL 层迁移:
目标表必须提前建好,结构与源表一致(包括字符集、排序规则、索引),但可去掉不必要的二级索引(归档表一般只按时间查);主键保留,否则后续删源数据时难以精准定位。
示例归档语句:
INSERT INTO archive_db.order_log_2022 SELECT * FROM main_db.order_log WHERE created_at >= '2022-01-01' AND created_at < '2023-01-01';注意:该语句需在事务内执行,且确保
max_allowed_packet 足够大(否则大批量插入会报 Packet too large)。
归档后记得清理统计信息和监控残留
归档不是删完就结束。容易被忽略的点:
-
INFORMATION_SCHEMA.TABLES中的DATA_LENGTH/INDEX_LENGTH不会实时更新,需等下次ANALYZE或重启才准;别靠它立刻判断空间是否释放 - 如果用了 pt-archiver 工具,它默认不删 binlog,归档完要手动
PURGE BINARY LOGS BEFORE '2024-01-01'(前提是你确认从库已同步完) - 监控项如
table_rows是估算值,归档后可能不准;建议改用SELECT COUNT(*)抽样校验关键表行数 - 归档脚本里没写错误重试逻辑?网络抖动或锁冲突导致某一批失败,后续批次会跳过——得加
ROW_COUNT()判断实际影响行数,不为 0 才继续










