为什么这种隐式连接的规划方式与显式连接不同?

Eva*_*oll 5 postgresql performance join execution-plan postgresql-9.5 postgresql-performance

在这个答案中,我解释了 SQL-89 的隐式语法。
但是我在玩的时候注意到不同的查询计划:

EXPLAIN ANALYZE
  SELECT *
  FROM (values(1)) AS t(x), (values(2)) AS g(y);

                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
 Planning time: 0.052 ms
 Execution time: 0.020 ms
(3 rows)
Run Code Online (Sandbox Code Playgroud)

与此相反:

EXPLAIN ANALYZE
  SELECT *
  FROM (values(1)) AS t(x)                      
  CROSS JOIN (values(2)) AS g(y);
                                           QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Subquery Scan on g  (cost=0.00..0.02 rows=1 width=4) (actual time=0.004..0.005 rows=1 loops=1)
   ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
 Planning time: 0.075 ms
 Execution time: 0.027 ms
(4 rows)
Run Code Online (Sandbox Code Playgroud)

为什么其中之一会显示Subquery Scan
隐式语法不是重写为与显式语法相同吗?

Erw*_*ter 10

隐式语法不是重写为与显式语法相同吗?

不必要。您建立在稍微不正确的假设上。就像我在参考问题下解释的那样:

FROM列表中逗号分隔的项目显式符号几乎相同,但并不完全相同CROSS JOIN。显式连接绑定更强。在某些情况下,查询计划器必须以不同的方式处理这两种情况。

显然,规划器足够聪明,能够VALUES使用简化的计划处理具有单行表达式的表达式。我们看到VALUES表达式中不止一行的更复杂的计划:

EXPLAIN ANALYZE
SELECT *
FROM  (VALUES (1), (2)) t(x)
    , (VALUES (2), (3)) g(y);
Run Code Online (Sandbox Code Playgroud)
 Nested Loop  (cost=0.00..0.11 rows=4 width=8) (actual time=0.059..0.064 rows=4 loops=1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4) (actual time=0.004..0.004 rows=2 loops=1)
   ->  Materialize  (cost=0.00..0.04 rows=2 width=4) (actual time=0.025..0.026 rows=2 loops=2)
         ->  Values Scan on "*VALUES*_1"  (cost=0.00..0.03 rows=2 width=4) (actual time=0.001..0.002 rows=2 loops=1)
Run Code Online (Sandbox Code Playgroud)

对于VALUES用逗号分隔的表达式,简化查询计划更容易。当受显式连接约束时,Postgres 需要与其他逗号分隔FROM项组合之前考虑连接条件。我希望我们在这种情况下看到的“subqery scan”是这种情况下更复杂的代码路径的(完全无害的)副作用。