自从 PostgreSQL 推出了执行 LATERAL
连接的功能以来,我一直在阅读它,因为我目前正在为我的团队做复杂的数据转储,其中包含许多低效的子查询,这些子查询构成了整体查询花四分钟或更长时间。
我知道 LATERAL
连接可能会帮助我,但即使在阅读了像 this one 这样的文章之后来自 Heap Analytics,我仍然不太了解。
LATERAL
连接的用例是什么? LATERAL
连接和子查询有什么区别?
最佳答案
是什么 LATERAL
加入?
此功能是在 PostgreSQL 9.3 中引入的。 The manual :
Subqueries appearing in
FROM
can be preceded by the key wordLATERAL
. This allows them to reference columns provided by precedingFROM
items. (WithoutLATERAL
, each subquery is evaluated independently and so cannot cross-reference any otherFROM
item.)Table functions appearing in
FROM
can also be preceded by the key wordLATERAL
, but for functions the key word is optional; the function's arguments can contain references to columns provided by precedingFROM
items in any case.
那里给出了基本的代码示例。
更像是一个相关子查询
A LATERAL
join 更像是一个 correlated subquery ,不是普通子查询,在 LATERAL
右侧的表达式中join 对它左边的每一行计算一次 - 就像一个相关 子查询 - 而普通子查询(表表达式)只计算一次。 (不过,查询规划器有办法优化两者的性能。)
并排提供代码示例的相关答案,解决了相同的问题:
要返回多列,LATERAL
加入通常更简单、更干净、更快。
另外,请记住,相关子查询的等效项是 LEFT JOIN LATERAL ... ON true
:
子查询不能做的事情
有的东西LATERAL
join 可以,但是(相关的)子查询不能(容易)。相关子查询只能返回单个值,不能返回多列,也不能返回多行——裸函数调用除外(如果它们返回多行,则结果行相乘)。但即使某些设置返回函数也只允许在 FROM
中使用条款。喜欢unnest()
在 Postgres 9.4 或更高版本中具有多个参数。 The manual:
This is only allowed in the
FROM
clause;
所以这行得通,但不能(轻易)替换为子查询:
CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2); -- implicit LATERAL
,
中的逗号 ( FROM
) clause 是 CROSS JOIN
的简称.
LATERAL
对于表函数自动假定。
关于UNNEST( array_expression [, ... ] )
的特例:
SELECT
中的集合返回函数列表
您还可以使用返回集合的函数,例如 unnest()
在SELECT
直接列出。这曾经在同一个 SELECT
中表现出不止一个这样的功能令人惊讶的行为列出 Postgres 9.6。 But it has finally been sanitized with Postgres 10现在是一个有效的替代方案(即使不是标准 SQL)。见:
基于上面的例子:
SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM tbl;
比较:
用于 pg 9.6 的 dbfiddle here
第 10 页的 dbfiddle here
澄清错误信息
For the
INNER
andOUTER
join types, a join condition must be specified, namely exactly one ofNATURAL
,ON
join_condition, orUSING
(join_column [, ...]). See below for the meaning.
ForCROSS 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 <b>ON TRUE</b>;
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;
关于sql - PostgreSQL 中的 LATERAL JOIN 和子查询有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28550679/