【问题标题】:Postgres nested loop orderPostgres 嵌套循环顺序
【发布时间】:2011-05-04 22:55:58
【问题描述】:

我有以下疑问:

SELECT t1.c1 FROM t1,t2 WHERE t1.c2 = 'X' AND t1.id = t2.id AND t2.c3 = 'Y';

Postgres 为这个查询生成两个计划,类似于:

Nested Loop (rows=1 width=7) (actual rows=1 loops=1)
    -> Index Scan using idx1 on t1 (rows=1 width=7) (actual rows=4 loops=1)
    -> Index Scan using idx2 on t2 (rows=1 width=7) (actual rows=0 loops=7)

或:

Nested Loop (rows=1 width=7) (actual rows=1 loops=1)
    -> Index Scan using idx2 on t2 (rows=4 width=7) (actual rows=1000000 loops=1)
    -> Index Scan using idx1 on t1 (rows=1 width=7) (actual rows=0 loops=1000000)

因此,有时选择 t1 作为外循环,有时选择 t2。如果选择第二个计划,性能绝对是糟糕的。

我的问题是,如何强制 Postgres 始终使用第一个查询计划,t1 在外循环?

【问题讨论】:

    标签: postgresql inner-join


    【解决方案1】:

    确保您定期运行ANALYZE。估计还有很长的路要走。

    顺便说一句,Postgres 可能不在乎,但您可能使用

    获得更好的结果
    SELECT T1.c1 FROM t1 JOIN t2 ON t1.id=t2.id
    WHERE t1.c2='X' AND t2.c3='Y';
    

    【讨论】:

    • ANALYZE 定期运行,我可能在那方面可以做更多的调整,但我想知道是否有办法强制嵌套循环顺序,因为我不确定 ANALYZE 会解决问题。我尝试使用 JOIN 但得到了相同的结果。
    • 除非您将情况过于简化,否则在此示例中未运行 ANALYZE。 t2 的估计行数减少了 250,000 倍。或者 c2 和 c3 的分布很不平衡。您可以尝试使用半连接 t1 NATURAL JOIN (SELECT * FROM t2 WHERE t2.c3='Y') AS t3 WHERE 等重写它,但请注意,如果 c2 和 c3 的分布相反,您将需要第二个计划而不是第一个计划!
    • 例子确实简化了。我会尝试半连接。
    【解决方案2】:

    尝试使用左连接?由于 t2.c3 上的子句,这应该强制连接顺序并返回相同的结果:

    SELECT t1.c1
    FROM t1 LEFT JOIN t2 ON t1.id = t2.id
    WHERE t1.c2 = 'X' AND t2.c3 = 'Y';
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 2020-04-16
      • 1970-01-01
      • 2020-04-12
      • 1970-01-01
      相关资源
      最近更新 更多