小编典典

LATERAL JOIN和PostgreSQL中的子查询有什么区别?

sql

由于Postgres具有LATERAL连接的能力,因此我一直在阅读,因为我目前为团队执行复杂的数据转储,其中包含许多效率低下的子查询,使得整个查询需要四分钟或更长时间。

我知道LATERAL联接可能会为我提供帮助,但是即使从Heap Analytics中阅读了类似这样的文章,我仍然不太了解。

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


阅读 325

收藏
2021-04-15

共1个答案

小编典典

什么是一个LATERAL加入?
该功能是PostgreSQL 9.3中引入的。
引用手册:

出现的子查询FROM之前可以带有关键字 LATERAL。这使他们可以引用前面的FROM项目提供的列 。(没有LATERAL,每个子查询都是独立评估的,因此不能交叉引用任何其他FROM项目。)

出现的表函数FROM也可以在关键字之后LATERAL,但是对于函数,关键字是可选的;例如:FROM在任何情况下,函数的参数都可以包含对前面各项提供的列的引用。

更像是相关子查询
甲LATERAL联接更像是一个相关子查询,而不是一个简单的子查询,在该表达式的右侧LATERAL连接中一次左的它的每一行评价-就像一个相关子查询-而平原子查询(表表达式)一次只要。(不过,查询计划器可以通过其中一种方法来优化性能。)
并排使用示例代码的相关答案,解决了相同的问题:

优化GROUP BY查询以检索每个用户的最新行
对于返回多个列,LATERAL联接通常更简单,更干净,更快。
另外,请记住,相关子查询的等效项是LEFT JOIN LATERAL … ON true:

多次调用带有数组参数的set-returning函数
子查询不能做的事情
有是事,一个LATERAL连接可以做,但一(相关的)子查询不能(容易)。相关的子查询只能返回一个值,不能返回多列,不能返回多行-裸函数调用(如果结果行返回多行,则结果行相乘)除外。但是,即使某些子集返回函数也只能在该FROM子句中使用。与unnest()Postgres 9.4或更高版本中的多个参数一样。手册:

这仅在FROM子句中允许;

因此这可行,但不能(轻松地)用子查询替换:

CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

子句中的逗号(,)FROM是的缩写CROSS JOIN。LATERAL表功能自动假定。关于以下特殊情况UNNEST( array_expression [, … ] ):

如何声明仅在FROM子句中允许使用set-returning-function?
SELECT列表中的集合返回功能
您还可以像unnest()在SELECT列表中一样直接使用返回集合的功能。在过去的SELECTPostgres 9.6列表中,它经常表现出令人惊讶的行为,并且具有多个这样的功能。但是它终于用Postgres 10进行了消毒,并且现在是有效的替代方法(即使不是标准的SQL)。看:

SELECT子句中的多个返回集合的函数的预期行为是什么?
在以上示例的基础上:

SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

澄清错误信息
手册:

对于INNER和OUTER连接类型,必须指定一个连接条件,即NATURAL、、ON join_condition或USING(join_column [,...])中的一个。含义见下文。对于CROSS JOIN,这些子句都不会出现。

因此,这两个查询是有效的(即使不是特别有用):

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;
2021-04-15