具有较高 OFFSET 的同一查询的不同执行计划

问题描述 投票:0回答:1

我面临数据库中

select
的问题。我在循环中调用相同的查询并仅更改
offset
。前 9 个查询非常快(大约 300 毫秒),但第 10 个及后续查询大约需要 40 秒。

我将尽可能多的日志打印到我的 postgresql 日志中,我看到了两件事:

  1. 在此日志之后:

    2024-03-20 21:20:00 2024-03-20 20:20:00.105 UTC [34] LOG:  disconnection: session time: 0:15:37.444 user=admin database=registry host=172.20.0.1 port=46436`
    

    数据库再次正常工作,快速调用 9 个查询,然后再次变慢 - 直到再次断开连接。在代码中设置断点并重新启动数据库也有帮助,但这不是解决方案。另外,当我停留在断点上时调用类似的东西时:

    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'your_database_name';
    

    有助于无延迟地通过接下来的 9 个查询,但像以前一样 - 这不是一个解决方案。

  2. 当查询速度变慢时,我看到的执行计划与查询速度快时不同。这些是我看到的差异:

    • 较慢的查询具有更好的执行成本
    • 查询有其他操作或操作顺序
    • 较慢的查询具有参数(如 $1、$2 等),而不是出现在称为快速的查询中的值

这里是差异链接:https://www.diffchecker.com/vYu3Ejrp/

我也尝试过:

  • 更改 postgres 属性(内存等资源)
  • 更改 hikari 中的最大连接池
  • 禁用休眠缓存
  • 还有更多我现在可能不记得的事情

当我使用复杂性较低的查询时(例如:我删除一个

where
join
子句),它工作得很好,我可以在循环中调用任意数量的查询。另外,当我添加一些索引时,问题就消失了。但对我来说这太奇怪了。我想如果是效率问题那么数据库应该总是缓慢地回答,而不是在几次查询之后。我说得对吗?


为了总结这一点,我可以补充一点

  • 当我使用
    entityManager.createNativeQuery()
    而不是
    entityManager.createQuery()
    并使用标准生成器进行制作时,一切正常。
  • 当我通过 dbeaver 中的脚本调用此查询时(循环 2000 次),没问题。
  • 当我用 Python 传递这个查询时,它工作得很好。

但是从日志中我看到问题是数据库执行查询的时间太长了。

java database postgresql spring-boot hibernate
1个回答
0
投票

我想如果是效率问题那么DB应该总是缓慢地回答,而不是在几次查询之后

PREPARE
声明的文档说:

准备好的语句可以使用通用计划或自定义计划来执行。 ...当前的规则是前五次执行是通过自定义计划完成的,并计算这些计划的平均估计成本。然后创建通用计划,并将其估计成本与平均定制计划成本进行比较。如果通用计划的成本没有比平均自定义计划成本高出太多,那么后续执行将使用通用计划,从而使重复的重新计划看起来更可取。

这解释了为什么你的执行计划在 some 执行后发生变化(不知道你是如何达到 nine 执行的)以及为什么如果你强制

plan_cache_mode
它是稳定的。

根本原因是通用计划(即使用变量代替文字的计划)的成本错误(太低),因此切换后性能会下降。

© www.soinside.com 2019 - 2024. All rights reserved.