PostgreSQL default_statistics_target 没有改进行估计
Posted
技术标签:
【中文标题】PostgreSQL default_statistics_target 没有改进行估计【英文标题】:PostgreSQL default_statistics_target not improving row estimation 【发布时间】:2020-06-30 11:22:42 【问题描述】:我正在尝试优化我们在 Postgres 上的查询,这有时需要几分钟才能使用大型表。开始查看查询计划,发现使用EXPLAIN ANALYZE
运行时估计的行数与实际行数相差近 1000 倍。
这将我引向参数default_statistics_target
,它控制ANALYZE
命令采样的行数,以收集查询计划器使用的统计信息。正如少数博客所建议的那样,我通过增加值将其设置为1000
并将事件设置为10000
的最大允许值进行了实验。
每次运行ANALYZE
以确保其统计信息已更新。但令人惊讶的是,这根本没有改善行估计。事实上,它进一步降低了估计值,这似乎很奇怪。
还通过将值减小到10
进行了测试。这似乎使计数有所改善。所以我很困惑,如果参数真的做了我认为它做的事情。或者,如果有其他方法可以改进行估计。任何帮助将不胜感激。
Postgres 版本:9.6
查询计划:在最后的索引扫描步骤中,估计为 462,但实际为 1.9M。 https://explain.depesz.com/s/GZY
更改default_statistics_target = 1000
后,索引扫描步骤中的行是
-> (cost=0.57..120.42 rows=114 width=32) (actual time=248.999..157947.395 rows=1930518 loops=1)
将其设置为default_statistics_target = 10
,计数为:
-> (cost=0.57..2610.79 rows=2527 width=32) (actual time=390.437..62668.837 rows=1930518 loops=1)
附:正在考虑的表有超过 1 亿行。
【问题讨论】:
InitPlan 计算的值会不会是event_name_id
最常见的值?查询是什么?
@LaurenzAlbe 添加了查询。是的。子查询返回的值将是事件表中 event_name_id 的最常见值。那应该得到更好的估计吧?
【参考方案1】:
这看起来像是一个相关问题。规划器假定 project_id、event_name_id 和“timestamp”上的条件是独立的,因此会乘以它们的估计选择性。如果它们不是独立的,那么再多的传统统计数据也无济于事。也许你需要extended statistics
此外,在制定计划时,它甚至不知道 event_name_id 将与哪个值进行比较,因为 $0 直到运行时才确定,因此它不能为此使用特定于值的统计信息。您可以手动执行子查询,然后将结果值硬编码到查询中的那个位置,这样规划器在规划时就知道该值是什么。
【讨论】:
感谢您指向扩展统计信息。如果有帮助,会检查。并且 $0 值直到运行时才知道是有道理的,因此它不知道它将是最常见的值。所以我猜默认情况下它假定一般非频繁值的统计数据(很多)。 可悲的是,从 Postgres 10 添加了扩展统计信息。我们使用的是 9.6。不升级版本可以做其他事情吗? 当计划为 0 美元时,我认为它只是假设返回的行将是估计的行数除以估计的不同值,所以是的,许多稀有值的存在会拖累估计值。自己运行子查询然后硬编码实际值应该至少有助于估计,尽管您可能也有在 9.6 中无法帮助的相关性。但对我来说,更好的行估计实际上会导致更好的计划并不明显。也许您返回的行数太多以至于 seq 扫描会更好,但这还很不清楚。 在 9.6 中,max_parallel_workers_per_gather 默认为零。如果您有多个 CPU,您可以尝试更改它。但是并行查询在当时还很原始,所以它可能不是很有帮助。花在升级上的时间通常比花在解决因不升级引起的问题上的时间要好。 对。 9.6 也可能很快进入不受支持的版本列表。肯定会建议升级。感谢您抽出宝贵时间对此进行调查。以上是关于PostgreSQL default_statistics_target 没有改进行估计的主要内容,如果未能解决你的问题,请参考以下文章
prometheus使用postgresql-adapter连接postgresql
PostgreSQL介绍以及如何开发框架中使用PostgreSQL数据库