
你有一个上亿行的日志表,查询越来越慢,磁盘空间告急。你要删掉半年前的数据。
直接跑DELETE FROM logs WHERE created_at < ‘2026-01-01’?
千万别。
这条语句会锁住大量行,产生几十GB的binlog,主从延迟可能飙到几小时,而且万一你中途想取消,回滚需要同样的时间。
今天介绍一个专业工具:pt-archiver。它能把“一次删千万”拆成“每次删一小批”,在后台慢慢啃,不影响线上业务。
批量删除的正确姿势:先弄懂pt-archiver
pt-archiver是Percona Toolkit中的明星工具,专门设计用于低影响地归档或删除MySQL数据。核心思路很简单:每次取一小批数据(比如1000行),处理完再取下一批,每批独立提交事务。
关键参数:
实战:清理3个月前过期的订单数据
第一步:安装Percona Toolkit
bash
# Ubuntu/Debian wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb sudo apt-get update sudo apt-get install -y percona-toolkit # CentOS/RHEL sudo yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm sudo yum install -y percona-toolkit
第二步:确认删除条件有索引
pt-archiver的效率几乎完全取决于索引。假设要删orders表中created_at < '2026-02-01'的历史订单:
sql
# 确认索引存在且高效 EXPLAIN SELECT * FROM orders WHERE created_at < '2026-02-01' \G
如果type是ALL,说明没走索引,需要先建复合索引:
sql
ALTER TABLE orders ADD INDEX idx_created_at (created_at);
第三步:Dry-run测试
bash
pt-archiver --source h=localhost,D=mydb,t=orders,u=root,p=xxx \ --where "created_at < '2026-02-01'" \ --purge \ --limit 1000 \ --dry-run
观察SQL是否走了正确的索引,rows扫描数是否合理。
第四步:正式执行(带索引优化)
bash
pt-archiver --source h=localhost,D=mydb,t=orders,u=root,p=xxx \ --where "created_at < '2026-02-01'" \ --purge \ --limit 1000 \ --txn-size 1000 \ --sleep 1 \ --statistics
参数解读:
--purge:只删除,不归档到其他表--limit 1000:每批取1000行--txn-size 1000:每1000行提交一次事务--sleep 1:每批暂停1秒,避免IO打满--statistics:结束时显示统计信息
pt-archiver的参数陷阱要避开
陷阱一:自增ID最大的行删不掉
这是默认行为。pt-archiver为了防止删除正在写入的最新数据,会自动跳过自增ID最大的那一批。
如果要删到最新,加--no-safe-auto-increment参数。
陷阱二:没走预期索引
默认情况下,pt-archiver会按主键顺序扫描。如果删除条件不是按主键,效率会极差。
强制指定业务索引:
bash
pt-archiver --source h=localhost,D=mydb,t=logs,i=idx_created_at \ --where "created_at < '2026-02-01'" \ --purge --limit 1000 --no-ascend
i=idx_created_at强制使用时间索引,--no-ascend禁用默认的主键升序扫描。
陷阱三:没测试直接跑
大表操作前务必在从库或测试环境先跑一遍,用EXPLAIN确认执行计划。
实际效果对比
有个真实案例:一张2亿行的用户行为日志表,需要删除1.5亿行旧数据。
| 方案 | 耗时 | 主从延迟 | 业务影响 |
|---|---|---|---|
| 直接DELETE | 12小时+ | 延迟3小时 | 全链接锁表,网站间歇性不可用 |
| pt-archiver | 8小时 | 延迟<10秒 | 无感知 |
虽然pt-archiver总耗时更长,但对线上业务几乎没影响,可以随时中断,中断后还能从断点继续。
什么时候不能用pt-archiver?
最后一句
直接DELETE大表的风险远比你想象的大。pt-archiver把重型操作拆解成可控的小批量任务,配合正确的索引,才能实现“数据清理效果”和“业务平稳运行”二者兼得。
下次接到“删历史数据”的需求,别直接敲DELETE了。先用pt-archiver --dry-run看看计划,确认索引,再加--purge优雅执行。




