加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-13 16:48:16 所属栏目:百科 来源:网络整理
导读:由于Postgres有能力做LATERAL加入,我一直在读,因为我目前为我的团队做复杂的数据转储,有很多低效的子查询,使整个查询需要四分钟或更长时间。 我知道LATERAL加入可能能够帮助我,但即使在阅读来自Heap Analytics的文章(例如this one)后,我仍然不太明白。
由于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是无效的。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读