在PostgreSQL中,LATERAL和一个子查询有什么区别?

前端之家收集整理的这篇文章主要介绍了在PostgreSQL中,LATERAL和一个子查询有什么区别?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
由于Postgres有能力做LATERAL加入,我一直在读,因为我目前为我的团队做复杂的数据转储,有很多低效的子查询,使整个查询需要四分钟或更长时间。

我知道LATERAL加入可能能够帮助我,但即使在阅读来自Heap Analytics的文章(例如this one)后,我仍然不太明白。

LATERAL加入的用例是什么? LATERAL连接和子查询之间有什么区别?

更像是一个相关的子查询

LATERAL连接(Postgres 9.3)更像是一个correlated subquery,而不是一个普通的子查询。像@Andomar pointed out一样,LATERAL连接右侧的函数或子查询通常必须被评估多次 – 对于LATERAL连接的每一行,一次 – 就像一个相关的子查询,而一个纯子查询只被评估一次。这个相关的答案有并行的代码示例,解决同样的问题。

> Optimize GROUP BY query to retrieve latest record per user

当返回多个列时,LATERAL连接通常更简单,更清洁和更快。
另外,请记住,相关子查询的等价物是LEFT JOIN LATERAL .. ON TRUE:

> Call a set-returning function with an array argument multiple times

阅读手册

我强烈建议您阅读LATERAL的手册。它比我们将在这里提出的答案更有权威:

> http://www.postgresql.org/docs/current/interactive/queries-table-expressions.html#QUERIES-LATERAL
> http://www.postgresql.org/docs/current/interactive/sql-select.html

查询不能做的事情

有一些事情,一个LATERAL连接可以做,但(相关)子查询不能(轻松)。相关子查询只能返回单个值,而不能返回多个列,而不返回多个行(除了裸函数调用(如果返回多行,则乘以结果行)。但是,即使某些set返回函数只允许在FROM子句中。像Postgres 9.4中带有多个参数的新的unnest()。 Per documentation:

This is only allowed in the FROM clause;

所以这工作,但不能轻易地替换为子查询

CREATE TABLE tbl (a1 int[],a2 int[]);

SELECT *
FROM   tbl t,unnest(t.a1,t.a2) u(elem1,elem2);  -- implicit LATERAL

(FROM子句中的逗号(,)是CROSS JOIN的短标记
对于诸如unnest()的表函数自动假定为LATERAL。

更多关于UNNEST(array_expression [,…])的特殊情况下的关于dba.SE的后面的问题:

> How do you declare a set-returning-function to only be allowed in the FROM clause?

澄清错误信息

The manual clarifies misleading information here:

For the INNER and OUTER join types,a join condition must be
specified,namely exactly one of NATURAL,ON join_condition,
or USING (join_column [,…]). See below for the meaning.
For CROSS JOIN,none of these clauses can appear.

所以这些都是有效的(即使不是特别有用):

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t,LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

虽然这不是:

  
   
  SELECT * FROM tbl t LEFT JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t; 

  

这就是为什么@Andomar’s代码示例是正确的(CROSS JOIN不需要连接条件),@Attila’s是无效的。

猜你在找的Postgre SQL相关文章