归档前必须确认三个检查点:时间字段有索引以防锁表;冷备库表结构(含默认值、约束、字符集及时区行为)与源表一致;归档窗口避开业务高峰且事务不超max_allowed_packet和innodb_lock_wait_timeout。

归档前必须确认的三个检查点
不加判断直接删老数据,等于给线上库埋雷。归档动作本质是「先搬后删」,但前提是搬得稳、删得准、查得到。务必确认:
-
WHERE条件里的时间字段有索引,否则DELETE会锁表几十秒甚至更久 - 目标冷备库的
INSERT表结构与源表完全一致(含默认值、约束、字符集),尤其注意TIMESTAMP和DATETIME的时区行为差异 - 归档窗口期要避开业务高峰,且整个事务不能超 MySQL 的
max_allowed_packet和innodb_lock_wait_timeout
用 INSERT … SELECT + DELETE 分两步最可控
别用存储过程封装一个「自动删+自动插」的大事务——一旦中间失败,状态难回滚。拆成原子操作更稳妥:
- 第一步:用
INSERT INTO cold_db.order_archive SELECT * FROM prod_db.orders WHERE create_time 迁移数据;加上 <code>LIMIT 10000分批插入,避免长事务阻塞 - 第二步:确认插入行数匹配后,再执行
DELETE FROM prod_db.orders WHERE create_time - 两步都加
SELECT ROW_COUNT()检查实际影响行数,防止条件写错导致误删
存储过程里必须带事务控制和错误捕获
MySQL 存储过程默认不自动回滚,出错就停在半途。关键逻辑必须包在 DECLARE EXIT HANDLER FOR SQLEXCEPTION 里:
- 开头加
START TRANSACTION,结尾显式COMMIT或ROLLBACK - 每次
INSERT后立刻用GET DIAGNOSTICS @rowcount = ROW_COUNT记录成功条数 - 如果
@rowcount = 0,说明没数据可搬,直接退出,避免空跑 - 别依赖
@@ERROR,它只存上一条语句状态,多语句下不可靠
定时调度别只靠 EVENT,加一层 Shell 脚本兜底
MySQL EVENT 在实例重启后可能失效,且无法跨库连冷备库执行 INSERT。推荐组合方案:
- 存储过程只负责从源库读、向本地临时表写(或生成 SQL 文件)
- 用 Linux
crontab调用mysql -h cold-host -u user -p'pwd' cold_db -e "LOAD DATA INFILE ..."导入 - 脚本里加
mysqladmin ping -h prod-host和mysqladmin ping -h cold-host双活检测 - 所有日志输出到
/var/log/archive/order_daily.log,方便 grep 错误码
归档不是一劳永逸的动作,create_time 字段是否被业务代码动态更新、归档后分区表的 EXCHANGE PARTITION 是否同步、冷备库备份策略是否覆盖新归档表——这些细节漏掉一个,半年后查不到订单就是真问题。

















