执行计划没变,执行时快时慢是怎么回事?

数据库 Oracle
SQL的性能又回到了从前,看样子加大WORK_MEM并没有有效的改善SQL性能。回过头来想想也是,哪怕因为排序缓冲超了一点,做了硬盘排序,也不可能有20秒的性能影响。

​今天遇到D-SMART产品本身的一个性能问题,我准备用D-SMART给一套Oracle数据库做个巡检,发现居然任务因为一条SQL超时而异常了。通过日志发现是一条分析某个指标的SQL。

图片

图片

执行时间居然高达229秒,巡检报告中设定了SQL超时时间是180秒,而如果巡检的时间区间超过一个半月,则这条sql的执行时间介于170秒到250秒之间,就经常会超时了。

图片

D-SMART的后台数据库是PG,这张表是一张TIMESCALEDB的表。表上也创建了适当的索引。通过explain分析看,执行计划也是正常的,通过这个分区索引做范围扫描,然后做聚合(Timescaledb会按照时间戳自动做数据分区)。通过D-SMART的PG数据库等待事件分析工具可以发现,数据文件读是排在前面的。

刚开始的时候我也没有仔细分析,通过EXPAIN发现sort buffer使用量接近20M,明显超出了WORK_MEM参数。于是我调整了WORK_MEM参数,重新执行了这条SQL。发现原来需要200多秒的SQL不到50毫秒就完成了。不过我还是留了个心眼,因为D-SMART分析工具里可以看出文件读占了比较靠前的位置。于是我重启了一下PG数据库,再次执行这条SQL。比刚才稍微慢了一点,大概80多毫秒。不过比起200多秒来,也提升不少。于是我和同事说,这条SQL的性能问题解决了,加大WORK_MEM参数就可以了。

老储还是在PG上有丰富的实战经验,他提醒我,验证PG的问题,重启数据库是没用的,文件缓冲会影响SQL的性能。搞了二十多年Oracle,总是用Oracle的思维来思考现在的数据库问题,这回又犯了类似的错误。于是我重新做了测试,关闭数据库,然后使用echo 3 > drop_caches命令清除OS缓冲,然后再进行测试。

令人遗憾的是,SQL的性能又回到了从前,看样子加大WORK_MEM并没有有效的改善SQL性能。回过头来想想也是,哪怕因为排序缓冲超了一点,做了硬盘排序,也不可能有20秒的性能影响。

公司的这套PG 14.4的环境是装在一台虚拟机上的,磁盘是SATA盘,性能确实不行。对于PG这样使用DOUBLE CACHE的数据库,文件缓冲确实可以对SQL性能有明显的帮助。而这种特性也会让PG数据库的同一条SQL语句在OS的不同状态下执行性能有较大的波动。下面我们通过一个例子来验证一下。

在做这个测试之前,我们先要安装一个插件-pgfincore,对这个插件有兴趣的朋友可以去https://github.com/klando/pgfincore 下载。Pgfincore是针对PG数据库的OS缓冲分析与操作的插件,一般被用户用来分析OS缓冲中的数据库表或者索引,也被部分用户用来预热数据,让部分热数据总是被缓冲在FILE CACHE中,从而让OS CACHE能够更好的发挥作用。

Pgfincore的功能十分强大,首先可以用来查看某张表或者索引在OS缓冲中的情况。比如:

图片

我检查的一个timescaledb的索引分区,总共有15.7万个page,其中13.9万个page在OS缓冲里了。

图片

第二个功能是把某张表或者索引的数据预热到OS CACHE里。这里要注意的是如果表是分区表,一定要直接预热分区,而不要使用表的名字,pgfincore不支持自动识别表分区。Timescaledb的一个表分区,原本这张表并没有完全被缓冲到内存里,通过调用pgfadvise_willneed函数,把这张表的所有数据都调用到OS缓冲中了。

第三个功能是备份和恢复某个场景下的OS CACHE。这对于一些十分关键的系统的预热十分有价值。比如说某个系统的某些热数据对于系统性能十分关键。当系统重启(特别是服务器重启)后的某个时间段里,数据没有预热完成之前,系统性能是会有较大影响的。如果我们在停机重启前,先备份OS CACHE中某些热表的缓冲情况,系统重启后立即预热这部分数据,则可以确保系统重启后立即恢复重启前的性能。

图片

首先在系统重启前将pgfincore的数据保存在pgfincore_snapshot表中,系统重启后使用pgfadvise_loader重新装载缓冲数据。

有了上面的基础知识,我们下面就来做一个实验。

图片

首先对OS缓冲做一个完全的清理。然后启动PG数据库。执行刚才有问题的那条SQL语句。

图片

我只截取了部分执行计划,因为针对每个分区,都是相同的扫描方式,先对索引做扫描,然后再回表。这条SQL执行了34秒多。

接下来我们先按照上面的流程再次关闭数据库,清理缓冲,然后把所有的索引分区都先预热一下,看看效果如何。

图片

可以看出,现在所有索引的OS缓冲项都是0,说明没有任何索引数据被缓存了。接下来预热,然后再次执行这条SQL。

图片

大家可以看到,预热后,这些索引分区都在OS缓冲里了,同样再把所有的表的数据也预热一下。再来执行刚才的SQL语句:

图片

大家可以看到,执行时间从34秒变成了31毫秒。实际上对于使用double cache的数据库来说,此类问题是十分常见的。此类数据库产品的同一条SQL在不同时间里执行的性能可能差异上百倍,但是其执行计划是完全相同的。这是因为DOUBLE CACHE的原因。Pgfincore插件为解决此类问题提供了一个很好的解决方案。利用snapshot/restore的方式,如果做一些适当的精细化管理,可以起到十分好的稳定关键业务SQL执行效率的作用。希望我的这个性能故障的案例能够给大家一些启示。​

责任编辑:武晓燕 来源: 白鳝的洞穴
相关推荐

2011-09-14 17:03:17

数据库执行计划解析

2021-04-24 12:01:08

MySQL数据库Mysql执行计划

2021-03-17 09:35:51

MySQL数据库explain

2023-09-21 10:55:51

MysqlSQL语句

2015-04-22 14:17:45

SQL SERVERMSSQL SERVE缓冲区

2021-05-28 10:46:36

MySQL执行计划

2010-04-16 09:27:18

Ocacle执行计划

2022-08-15 15:09:26

SQL数据库MySQL

2022-08-08 08:03:44

MySQL数据库CBO

2023-03-29 08:24:30

2024-09-12 15:16:14

2009-11-13 16:28:02

Oracle生成执行计

2021-02-20 08:40:19

HiveExplain底层

2020-09-15 08:44:57

MySQL慢日志SQL

2009-11-18 17:05:47

捕获Oracle SQ

2020-02-18 11:19:36

物联网病毒物联网IOT

2021-09-07 10:43:25

EverDB分布式执行

2009-11-10 16:00:05

Oracle执行计划

2020-12-25 08:52:53

SQLMysql 数据库

2022-02-15 07:36:21

SQLEXPLAIN数据库
点赞
收藏

51CTO技术栈公众号