PostgreSQL 手动更改查询执行计划以强制使用排序和顺序访问而不是全扫描

Posted

技术标签:

【中文标题】PostgreSQL 手动更改查询执行计划以强制使用排序和顺序访问而不是全扫描【英文标题】:PostgreSQL manualy change query execution plan to force using sort and sequential access instead of full scan 【发布时间】:2013-08-08 09:11:16 【问题描述】:

我有这样的简单查询:

SELECT  *
FROM    t1
WHERE   f1 > 42
        AND f2 = 'foo'
        AND f3 = 'bar'
ORDER BY f4 DESC 
LIMIT 10 OFFSET 100;

我有字段 f4 的索引(用于其他查询)。条件 "f1 > 42 AND f2 = 'foo' AND f3 = 'bar'" 不具有代表性,对应表 t1 中 70% 的记录。表中大约有 2 000 000 条记录,并且每天都在增长。此查询的查询计划说明显示使用整个表的 seq 扫描,然后执行排序和限制。

是否可以说 Postgres 以这种方式执行此查询:

    通过使用字段 f4 上的索引来遍历反向排序的行。 对于每一行,与条件 f1 > 42 AND f2 = 'foo' AND 进行比较 f3 = 'bar' 对应的话就拿去吧。 如果结果集大小大于限制,则停止迭代。

【问题讨论】:

您是否为该表上的规划器收集了统计信息? (ANALYZE t1;) 不,我在开发数据库版本上执行查询。生产数据库具有另一种数据性质。我希望看到所需的计划,然后在生产中执行该查询。 就是这样。查询计划取决于数据。如果您想在您的开发数据库上查看真实的查询计划 - 您需要与真实数据相似的数据。 我的猜测 - 开发数据库没有太多数据,postgres 决定直接从表中获取它,而不是在索引上浪费时间。 在将数据加载到数据库后不要忘记收集统计信息。 【参考方案1】:

Here 是查询计划器的配置。您可以操纵它们来更改查询计划(对于您的情况,此查询可以是简单的SET enable_seqscan = off;)。

但在您更改规划器配置之前 - 检查此表上的统计信息是否正确,并在需要时再次收集它们。

【讨论】:

基本上它可以工作,我有 x8 加速。但前提是我没有对任何 f1、f2 或 f3 编制索引。如果我在 f1 或 f2 或 f3 上有索引(我有),Postgres 不使用 f4 的反向索引扫描(和限制),并尝试在即 f2 上使用索引。看起来 WHERE 子句中的文件索引具有优先权。 @Ostrovski 尝试阅读查询计划 (EXPLAIN (ANALYZE, BUFFERS))。这可能是为什么 postgres 选择这样的计划的一些线索。【参考方案2】:

据我了解,目标不仅是手动更改执行计划,而且还要继续获得与生产环境类似的执行计划。在这种情况下,带有优化器定义的游戏并不完全可靠。考虑到数据在不断增长,我想建议在生产和开发中实施分区,这将稳定执行计划。这将减少在执行计划生成中出错的可能性。作为替代表可能会通过 f4 上的索引定期聚集。不幸的是,没有足够的信息来推荐准确的分区策略。

【讨论】:

很简单,可以按创建时间分区=) 但现在不能直接。谢谢!

以上是关于PostgreSQL 手动更改查询执行计划以强制使用排序和顺序访问而不是全扫描的主要内容,如果未能解决你的问题,请参考以下文章

使用 Drill 查询获取 PostgreSQL 执行计划

如何在 BigQuery 中手动强制报告运行?

如何在 postgresql 中获取正在运行的查询的执行计划?

PostgreSQL——查询优化——生成优化计划1

PostgreSQL——查询优化——生成优化计划1

PostgreSQL——查询优化——生成优化计划1