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

PostgreSQL手动更改查询执行计划,强制使用排序和顺序访问,而不是完全扫描,postgresql,indexing,query-optimization,sql-execution-plan,Postgresql,Indexing,Query Optimization,Sql Execution Plan,我有这样一个简单的问题: SELECT * FROM t1 WHERE f1 > 42 AND f2 = 'foo' AND f3 = 'bar' ORDER BY f4 DESC LIMIT 10 OFFSET 100; 我有字段f4的索引(用于其他查询)。条件“f1>42和f2='foo'和f3='bar'”不具有代表性,对应于表t1中70%的记录。表中大约有2000000条记录,而且每天都在增长。此查询的查询计划说明显示了对整个表使用s

我有这样一个简单的问题:

SELECT  *
FROM    t1
WHERE   f1 > 42
        AND f2 = 'foo'
        AND f3 = 'bar'
ORDER BY f4 DESC 
LIMIT 10 OFFSET 100;
我有字段f4的索引(用于其他查询)。条件“f1>42和f2='foo'和f3='bar'”不具有代表性,对应于表t1中70%的记录。表中大约有2000000条记录,而且每天都在增长。此查询的查询计划说明显示了对整个表使用seq扫描,然后执行排序和限制

可以这样说Postgres执行此查询吗:

  • 通过使用字段f4上的索引来迭代反向排序的行
  • 对于每一行,与条件f1>42和f2='foo'进行比较,并 f3=‘bar’,如果对应,则取它
  • 如果结果集大小大于限制,则停止迭代
  • 是查询计划器的配置。您可以操纵它们来更改查询计划(对于您的情况,对于此查询可以是简单的
    SET enable\u seqscan=off;

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

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



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

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

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

    你在这张桌子上为计划者收集统计数据了吗?(
    ANALYZE t1;
    )不,我对开发数据库版本执行查询。生产数据库具有另一种数据性质。我希望看到所需的计划,然后对生产执行该查询。就是这样。查询计划取决于数据。如果您想在dev DB上看到真实的查询计划,您需要与真实数据相似的数据。我猜,dev DB没有太多数据,postgres决定直接从表中获取数据,而不会在索引上浪费时间。在将数据加载到DB后,不要忘了收集统计数据。您是否在此表上为planner收集了统计数据?(
    ANALYZE t1;
    )不,我对开发数据库版本执行查询。生产数据库具有另一种数据性质。我希望看到所需的计划,然后对生产执行该查询。就是这样。查询计划取决于数据。如果您想在开发数据库上看到真实的查询计划,您需要与真实数据相似的数据。我猜,开发数据库没有太多数据,postgres决定直接从表中获取数据,而不会在索引上浪费时间。在将数据加载到数据库后,不要忘记收集统计数据。基本上,它可以工作,而且我有x8加速。但前提是我在任何f1、f2或f3上都没有索引。如果我在f1、f2或f3上有索引(我有),Postgres不使用f4反向索引扫描(和限制),并尝试在f2上使用索引。看起来WHERE子句中的文件索引具有优先级。@Ostrovski尝试读取查询计划(
    EXPLAIN(ANALYZE,BUFFERS)
    )。这可能是一些线索来解释为什么博士后会选择这样的计划。基本上,这是可行的,而且我已经提高了x8的速度。但前提是我在任何f1、f2或f3上都没有索引。如果我在f1、f2或f3上有索引(我有),Postgres不使用f4反向索引扫描(和限制),并尝试在f2上使用索引。看起来WHERE子句中的文件索引具有优先级。@Ostrovski尝试读取查询计划(
    EXPLAIN(ANALYZE,BUFFERS)
    )。这可能是postgres为什么选择这样的计划的一些线索。它很简单,可以按创建时间=)划分,但现在不能直接划分。非常感谢。它可以按创建时间=)进行简单分区,但现在不能直接分区。非常感谢。