1. 为什么每个 MySQL 运维迟早都要面对数据归档这件事
1.1 数据无限增长,性能却不会无限容忍
我接触过不少业务系统,上线头两年一切正常,到了第三年突然开始频繁报警:慢查询变多、磁盘空间告急、备份时间越来越长。这时候打开数据库一看,最大的一张表往往已经几亿行,占了几百个 G。大多数情况下,真正频繁访问的热数据只有最近几个月,那些一年前、两年前的历史数据躺在表里,既不会被业务查询命中,又拖慢了索引维护和全表扫描的效率。
这就是典型的“数据增长拖垮性能”场景。很多团队的第一反应是直接 DELETE FROM 大表 WHERE create_time < ...,结果往往更糟:一条 DELETE 锁住几百万行,主从延迟瞬间拉满,binlog 暴涨,甚至把生产库直接干宕机。更麻烦的是,DELETE 只是逻辑删除,磁盘空间不会自动释放,InnoDB 表碎片越滚越大,问题一点没解决。
数据归档这件事,本质上不是“删数据”,而是“把冷数据搬走”。把历史数据从在线库迁移到归档库或归档表,让在线表瘦身,让热查询更快,同时历史数据仍然保留着,需要的时候还能查。这几乎是大体量 MySQL 业务绕不开的必经之路。而我这些年用下来最顺手的工具,就是 Percona Toolkit 里的 pt-archiver。
1.2 为什么是 pt-archiver,而不是 delete + 定时任务
先说明白,pt-archiver 不是什么黑魔法,它就是 Percona Toolkit 套件里的一个命令行工具,专门用来高效、安全地批量归档 MySQL 表中的数据。网上关于它的教程很多,但大多停在“会用几个参数”的层面,真正把它玩明白、做到自动化无人值守、并且能在生产环境扛住压力的文章,确实不多。这篇我就把自己从入门到实战的全过程整理出来,该踩的坑和该注意的点都摊开讲。
它和普通 DELETE 最大的区别在于:
- 分批删除,每批默认只处理少量行,不会一次性锁大量数据,对在线业务影响极小。
- 可以在归档删除的同时,把数据写入另一个库/表,相当于“搬移”而不是“删除”。
- 支持按主键或唯一键递增扫描,走索引效率高,而且天然适合超大表的轮询清理。
- 有干跑模式、限速参数、延迟监控,方便你在生产环境小心翼翼地控节奏。
我见过有人用存储过程实现同样的归档逻辑,也不是不行,但维护成本高,而且并发和异常处理都需要自己写。pt-archiver 把这些全都内置了,一条命令行就能表达清楚,脚本化、自动化都非常方便。这就是我为什么坚持推荐它的原因。
这套方法适合谁?适合正在为 MySQL 大表发愁的 DBA、后端开发、运维工程师。不管你管理的表是千万级还是亿级,只要你有“历史数据要保留但不想影响在线性能”的需求,这篇文章都能给你一套可以直接落地的方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. pt-archiver 核心原理与关键参数
2.1 它的工作方式跟普通 DELETE 有什么本质区别
先理解 pt-archiver 的底层逻辑,后面用参数才不会懵。它不像普通 DELETE 那样“一次删一片”,而是按照你指定的条件,逐行或逐小批次扫描,每扫到一行就先处理(比如写入归档表),再从原表删除。
整个过程说起来很简单,但设计上有几个非常关键的细节:
第一,它是基于主键或唯一键做“游标式”遍历的。每次处理完一批,它会记录当前批次最后一条数据的主键位置,下一批从那个位置继续往下走。这样做的好处是:即使表数据量巨大,它也不需要全表扫描,而是沿着索引有规律地推进,每一批都能快速定位。
第二,它把“读取”和“删除”分开了。默认情况下,它会先 SELECT 一批数据,处理完这批之后,再发 DELETE 删除同一批。注意,这里的 SELECT 和 DELETE 是在同一个事务里吗?不一定。取决于你是否指定了 --txn-size。这块我建议你记住一个原则:如果你希望“读出来的数据不会被业务同时改掉”,就用事务把一批操作包起来;如果你追求对在线业务干扰最小,可以把事务调小,甚至不用长事务。
第三,它还考虑到了主从延迟。工具本
