运行缓慢的 Postgres 查询

Posted

技术标签:

【中文标题】运行缓慢的 Postgres 查询【英文标题】:Slow running Postgres query 【发布时间】:2019-02-13 21:43:21 【问题描述】:

我的数据库需要很长时间才能完成此查询。此 SQL 是从应用程序内部的 ORM (Hibernate) 生成的。我无权访问源代码。

我想知道是否有人可以查看以下 ANALYZE EXPLAIN 输出并建议我可以进行的任何 Postgres 调整。

我不知道从哪里开始,也不知道如何调整我的数据库来服务这个查询。

查询如下所示

select 
    resourceta0_.RES_ID as col_0_0_ 
from
    HFJ_RESOURCE resourceta0_ 
    left outer join HFJ_RES_LINK myresource1_ on resourceta0_.RES_ID = myresource1_.TARGET_RESOURCE_ID 
    left outer join HFJ_SPIDX_DATE myparamsda2_ on resourceta0_.RES_ID = myparamsda2_.RES_ID 
    left outer join HFJ_SPIDX_TOKEN myparamsto3_ on resourceta0_.RES_ID = myparamsto3_.RES_ID 
where 
    (myresource1_.SRC_RESOURCE_ID in ('4954427' ... many more))
    and myparamsda2_.HASH_IDENTITY=`5247847184787287691` and 
(myparamsda2_.SP_VALUE_LOW>='1950-07-01 11:30:00' or myparamsda2_.SP_VALUE_HIGH>='1950-07-01 11:30:00') 
    and myparamsda2_.HASH_IDENTITY='5247847184787287691' 
    and (myparamsda2_.SP_VALUE_LOW<='1960-06-30 12:29:59.999' or myparamsda2_.SP_VALUE_HIGH<='1960-06-30 12:29:59.999') 
    and (myparamsto3_.HASH_VALUE in ('-5305902187566578701')) 
limit '500'

执行计划如下所示:https://explain.depesz.com/s/EJgOq

编辑 - 更新以添加 depesz 链接。 编辑 2 - 添加了有关查询的更多信息。

【问题讨论】:

edit您的问题并将执行计划添加为formatted text,该屏幕截图无法阅读。或者将其上传到explain.depesz.com 为有问题的表添加create table 语句,包括所有索引也会有所帮助。 不要在末尾的“ where ”子句中使用“ in ”子句,而是可以做另一个连接条件吗?我不知道你从哪里得到那串数字,但我认为字符串搜索,特别是如果不是有序字符串列表,可能是关键放缓。 我经常发现,如果你将 where some_table.col1 in (1,2,3) 重写为 join (values (1),(2),(3) ) as t(x) on some_table.col1 = t.x 在 Postgres 中更快——尤其是对于非常大的 IN 列表 感谢您的反馈 - 我添加了此链接:explain.depesz.com/s/EJgOq 【参考方案1】:

缓慢的原因是错误的行数估计,这使得 PostgreSQL 选择嵌套循环连接。您几乎所有的时间都花在对hfj_res_link 的索引扫描上,该扫描重复了 1113 次。

我的第一次尝试是ANALYZE hfj_spidx_date,看看是否有帮助。如果是,请确保自动分析更频繁地处理该表。

下一次尝试是

SET default_statistics_target = 1000;

然后ANALYZE 如上所述。如果这有帮助,请使用ALTER TABLE 增加hash_identitysp_value_high 列上的STATISTICS

如果这也没有帮助,并且您有最新版本的 PostgreSQL,您可以尝试扩展统计信息

CREATE STATISTICS myparamsda2_stats (dependencies)
   ON hash_identity, sp_value_high FROM hfj_spidx_date;

然后再次ANALYZE 表,看看是否有帮助。

如果所有这些都无济于事,并且您无法正确估算,则必须尝试不同的角度:

CREATE INDEX ON hfj_res_link (target_resource_id, src_resource_id);

这应该会大大加快索引扫描速度,并为您提供良好的响应时间。

最后,如果以上都没有任何效果,您可以对这个查询使用禁止嵌套循环连接的粗略措施:

BEGIN;
SET LOCAL enable_nestloop = off;
SELECT /* your query goes here */;
COMMIT;

【讨论】:

谢谢 - 我尝试了所有这些建议(除了扩展统计信息 - 我在 postgres 9.6 上),没有明显的性能提升。我确实使查询变小了——这显着改进了查询。请参阅:慢速(原始):explain.depesz.com/s/EJgOq 快速(删除一些查询参数):explain.depesz.com/s/TdRP 是什么让慢速查询扫描所有这些索引 100%?这是我可以更改的 postgres 设置吗? 注意 - 快速查询是通过在原始查询中删除 and (myparamsda2_.SP_VALUE_LOW&lt;='1960-06-30 12:29:59.999' or myparamsda2_.SP_VALUE_HIGH&lt;='1960-06-30 12:29:59.999') 进行的(参见原始帖子)。我不明白删除一个 AND 语句会如何产生如此大的影响。 我稍后再看看,但索引必须有所作为。没用过吗? 您删除的条件是估计错误的条件,因此通过观察强调这是您的问题的原因。如果您可以重写查询以消除这种情况,事情应该会有所改善。

以上是关于运行缓慢的 Postgres 查询的主要内容,如果未能解决你的问题,请参考以下文章

Postgres 进程显示 100% CPU 但实际使用率为 6%,导致查询响应缓慢

Postgres 选择查询在使用 JDBC 时运行缓慢,但在从同一服务器在 PSQL 中运行时快速

在 postgres 上缓慢选择不同的查询

最佳实践:优化Postgres查询性能(上)

最佳实践:优化Postgres查询性能(上)

防止在 Postgres 中为特定查询使用索引