MySQL冷热分离归档必须确保INSERT与DELETE成对校验,推荐MySQL≥5.7下用分区表+事件调度器自动归档,核心是迁移事件而非分区本身;老版本可用宝塔Shell脚本(需幂等、条件一致、加锁),或PHP双库同步(分批、游标、状态标记、数对比告警);归档本质是安全搬移并验证,非定时删除或日志压缩。

INSERT INTO 和 DELETE 必须成对校验,否则冷热分离会直接丢数据。
MySQL 分区表 + 事件调度器自动归档(推荐用于新项目)
这是最接近“开箱即用”的方案,但前提是 MySQL ≥5.7 且启用了 event_scheduler。分区本身不移动数据,真正起作用的是你写的迁移事件。
常见错误现象:ALTER TABLE orders PARTITION BY RANGE (TO_DAYS(create_time)) 执行成功,但查询变慢依旧——因为没删旧分区,也没建归档表。
- 先创建归档表:
CREATE TABLE orders_archive LIKE orders,引擎建议用COMPRESSED InnoDB或MyISAM(节省空间) - 分区字段必须是整型或日期函数返回值,
create_time要转成TO_DAYS(create_time)才能 RANGE 分区 - 事件里不能只写
INSERT INTO orders_archive SELECT * FROM orders WHERE create_time ,必须加 <code>AND NOT EXISTS (SELECT 1 FROM orders_archive WHERE order_id = orders.order_id)防重 - 执行
DELETE前,用ROW_COUNT()检查上一步INSERT是否写入了预期行数,不一致就中止
宝塔计划任务调 Shell 脚本归档(兼容老版本 MySQL)
适合 MySQL 5.6 或 MyISAM 表,也适合不敢动分区结构的线上库。核心是导出和删除的 WHERE 条件必须完全一致,且脚本要有幂等性。
使用场景:订单表无主键、时间字段为 varchar、或 DBA 禁用 EVENT 权限。
- 脚本开头加锁:
if [ -f /tmp/archive_orders.lock ]; then exit 0; fi; touch /tmp/archive_orders.lock,末尾rm -f /tmp/archive_orders.lock -
mysqldump的--where参数里别用NOW(),改用DATE_SUB('2026-04-30', INTERVAL 180 DAY)这种固定日期,避免跨天执行时条件漂移 DELETE FROM orders WHERE create_time —— 这个日期必须和 dump 命令里的完全一样,建议从同一变量读取- 导出文件名带日期:
/www/backup/orders_cold_$(date +\%Y\%m\%d).sql,方便后续按需恢复
PHP 脚本双库同步归档(需要控制归档逻辑细节)
当你要在归档前加审计日志、做字段脱敏、或写入非 MySQL 存储(如 SQLite、S3 元数据表)时,必须用 PHP 主动拉取+写入。别依赖数据库自动行为。
性能影响:单次同步超过 10 万行会阻塞 Web 请求,必须分批 + 设置 set_time_limit(0)。
- 连接两个库:热库用
PDO(带事务),冷库用PDO或SQLite3(轻量) - 分页查冷数据:
SELECT * FROM orders WHERE create_time ,OFFSET 不要硬写,用上次最大 <code>id做游标更稳 - 每批插入后,立刻执行
UPDATE orders SET archive_status = 1 WHERE id BETWEEN ? AND ?,而不是最后统一删——避免中间失败导致重复归档 - 归档完成后,用
SELECT COUNT(*)对比热库标记数和冷库写入数,差值 > 0 就发告警
别踩这些坑:TTL、gzip 日志、expireAfterSeconds 都不是归档
看到 expireAfterSeconds 就配索引?看到 log.file_format 就调 max_files?这些动作只会让问题更隐蔽。
真正归档的关键动作只有一个:把数据从 A 地搬去 B 地,并确认 B 地可读、A 地已清、中间无丢失。其余都是配套。
-
createIndex({ "created_at": 1 }, { expireAfterSeconds: 2592000 })是定时删,不是归档;删完就没了,change stream 还监听不到完整文档 - ThinkPHP 开启
app_debug = false和database.debug = false才能砍掉 80% 日志体积,光压缩runtime/log/*.log是隔靴搔痒 - 用
mysqldump --single-transaction导出时,如果热库有长事务,dump 可能卡住或读到不一致快照——归档窗口期必须避开业务高峰
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











