数据库太大怎么办?pt-archiver安全清理历史数据

数据库太大怎么办?pt-archiver安全清理历史数据

你有一个上亿行的日志表,查询越来越慢,磁盘空间告急。你要删掉半年前的数据。

直接跑DELETE FROM logs WHERE created_at < ‘2026-01-01’?

千万别。

这条语句会锁住大量行,产生几十GB的binlog,主从延迟可能飙到几小时,而且万一你中途想取消,回滚需要同样的时间。

今天介绍一个专业工具:pt-archiver。它能把“一次删千万”拆成“每次删一小批”,在后台慢慢啃,不影响线上业务。

批量删除的正确姿势:先弄懂pt-archiver

pt-archiver是Percona Toolkit中的明星工具,专门设计用于低影响地归档或删除MySQL数据。核心思路很简单:每次取一小批数据(比如1000行),处理完再取下一批,每批独立提交事务。

关键参数:

  • --limit:每批取多少行,建议1000
  • --txn-size:多少行提交一次事务
  • --purge:只删除,不归档
  • --sleep:每批之间暂停时间,给服务器喘息机会

实战:清理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 --version

第二步:确认删除条件有索引

pt-archiver的效率几乎完全取决于索引。假设要删orders表中created_at < '2026-02-01'的历史订单:

sql

# 确认索引存在且高效
EXPLAIN SELECT * FROM orders 
WHERE created_at < '2026-02-01' \G

如果typeALL,说明没走索引,需要先建复合索引:

sql

ALTER TABLE orders ADD INDEX idx_created_at (created_at);

第三步:Dry-run测试

以下命令会用索引扫描数据,但只打印SQL不实际删除

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亿行旧数据。

方案耗时主从延迟业务影响
直接DELETE12小时+延迟3小时全链接锁表,网站间歇性不可用
pt-archiver8小时延迟<10秒无感知

虽然pt-archiver总耗时更长,但对线上业务几乎没影响,可以随时中断,中断后还能从断点继续

什么时候不能用pt-archiver?

  • 大批量全删(>80%):用分区表DROP PARTITION或新建表替换的效率更高
  • 有外键关联pt-archiver不会主动处理外键,可能导致失败
  • PXC集群:有已知限制,需谨慎测试

最后一句

直接DELETE大表的风险远比你想象的大。pt-archiver把重型操作拆解成可控的小批量任务,配合正确的索引,才能实现“数据清理效果”和“业务平稳运行”二者兼得。

下次接到“删历史数据”的需求,别直接敲DELETE了。先用pt-archiver --dry-run看看计划,确认索引,再加--purge优雅执行。

知识库

宝塔面板安全设置:这7项必须改

2026-5-13 15:15:59

知识库

SSH连接慢?这些配置让登录快10倍

2026-5-14 15:33:14

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧