pt-archiver 归档慢问题分析

文章分析了使用pt-archiver进行数据库归档时遇到的效率问题,特别是当表的主键为多列复合主键时,归档速度会变慢。原因是pt-archiver默认使用主键升序查询,导致扫描过多行。解决方案是为时间字段添加索引,并在pt-archiver中指定使用该索引,从而提高select和delete操作的效率。通过实例展示了优化前后SQL语句的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题发现

最近在给一些大表配置了归档任务后,发现一些表的归档比其他表慢很多,下面具体分析下原因。

2.问题原因

通过监控数据库中归档相关连接,发现归档程序在源库中执行的select 操作耗时很长,相关sql类似如下

在使用pt-archiver 进行归档时,如果我们不指定i参数(归档时使用该参数指定索引进行select查询),默认情况下 pt-archiver 在源端 select 和 delete时会用主键索引进行升序查询(下一次查询根据上次查询的主键最大值,作为本次范围查询的最小值)。如果表的主键是多列组成的复合主键,那么会导致where 条件过于复杂,影响语句执行效率。这时我们可以指定 --ascend-first 指定指使用复合索引最左前缀。

通常情况下使用主键索引来归档是没有问题的,比如上面的例子中归档999天之前的数据(id_times是时间字段),如果我们用的是自增主键,那么通常主键较小的记录,时间值也会较小,对于这样的表。通过主键归档通常不会有问题。(因为最小主键时间值也最小,所以扫描很少记录就能满足要求)但是如果表中的数据并不像我们想的这样,比如主键和时间字段没有成正比关系。那么根据主键去过滤满足小于某个时间条件的N条记录可能就需要扫描太多行,导致归档效率低下。

还是以我们上面的表为例子,看看表中的数据情况

这样的数据分布情况就导致我们根据主键索引归档效率极低。

3.问题处理

   那么怎么解决该问题呢?可以给id_times 字段加上索引,pt-archiver 归档时指定使用 id_times 字段索引。 这时源库select 和 delete 时都会使用 id_times 字段上的索引,效率就会高很多。

pt-archiver --source A=utf8mb4,h=源主机地址,P=3306,u=data_archiver_rw,p='xxxxx',D=test_db,t=test_table,i=idx_create_time --dest h=目的主机地址,P=3306,u=data_archiver_rw,p='xxxxx',D=test_db,t=test_table  --charset=utf8 --where 'create_time < DATE_SUB(CURDATE(),INTERVAL 15 DAY)' --progress 100000 --limit=1000 --txn-size 1000 --bulk-insert --bulk-delete --statistics --no-check-charset

这时源库的select和delete 类似如下:

#这里看到where 条件中时间字段指定了两次小于 DATE_SUB(),这个是因为在pt-archiver的where 条件中指定了两次(同事想通过这个来控制每次删除多久的数据)

SELECT /*!40001 SQL_NO_CACHE */ `p_key`,`id_cars`,`id_times`,`id_orders`,`face_counters`,`car_state`,`photo_path`,`id_city`,`min_score`,`avg_score` FROM `test_db`.`test_table` FORCE INDEX(`time`) WHERE (id_times < DATE_SUB(CURDATE(),INTERVAL 552 DAY) and id_times < DATE_SUB(CURDATE(),INTERVAL 550 DAY)) AND ((('2020-11-12 23:59:59' IS NULL OR `id_times` >= '2020-11-12 23:59:59'))) ORDER BY `id_times` LIMIT 1000;
#这里跟使用主键索引一样,本次访问的1000条记录中,最大的时间值,会作为下次最小的时间值,尽量减少不必要的扫描

DELETE FROM `test_db`.`test_table` WHERE (((('2020-11-12 23:59:53' IS NULL OR `id_times` >= '2020-11-12 23:59:53')))) AND (((('2020-11-12 23:59:59' IS NULL OR `id_times` <= '2020-11-12 23:59:59')))) AND (id_times < DATE_SUB(CURDATE(),INTERVAL 552 DAY) and id_times < DATE_SUB(CURDATE(),INTERVAL 550 DAY)) LIMIT 1000



默认情况下使用主键升序查询,源库select 和 delete如下(使用主键升序查询,还会有select max(id) 查询)

SELECT /*!40001 SQL_NO_CACHE */ `id`,`uid`,`city_code`,`awake_time`,`update_time` FROM `test_db`.`test_table` FORCE INDEX(`PRIMARY`) WHERE (awake_time < DATE_SUB(CURDATE(),INTERVAL 61 DAY) and awake_time < DATE_SUB(CURDATE(),INTERVAL 61 DAY)) AND (`id` < '1420865800') AND ((`id` >= '1208412567')) ORDER BY `id` LIMIT 1000

DELETE FROM `test_db`.`test_table` WHERE (((`id` >= '1208411550'))) AND (((`id` <= '1208412567'))) AND (awake_time < DATE_SUB(CURDATE(),INTERVAL 61 DAY) and awake_time < DATE_SUB(CURDATE(),INTERVAL 61 DAY)) LIMIT 1000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

渔夫数据库笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值