小编典典

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

sql

自从Postgres具备进行LATERAL连接的能力以来,我一直在阅读它,因为我目前为团队执行复杂的数据转储,其中包含许多效率低下的子查询,这些查询使整个查询花费了四分钟或更长时间。

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

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


阅读 241

收藏
2021-05-05

共1个答案

小编典典

什么 一个LATERAL加入?

该功能是PostgreSQL 9.3中引入的。
引用手册

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

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

此处提供了基本代码示例。

更像是 相关 子查询

LATERAL联接更像是一个相关子查询,而不是一个简单的子查询,在该表达式的右侧LATERAL连接中一次左的它的每一行评价-
就像一个 相关 子查询-而平原子查询(表表达式) 一次 只要。(不过,查询计划器可以通过其中一种方法来优化性能。)

子查询不能做的事情

事,一个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 [, ... ] )

SELECT列表中的集合返回功能

您还可以像unnest()SELECT列表中一样直接使用返回集合的功能。SELECT直到Postgres
9.6为止,它在同一列表中都具有不止一种这样的功能,因此表现出令人惊讶的行为。但是它终于用Postgres
10进行了消毒,
并且现在是有效的替代方法(即使不是标准的SQL)
在以上示例的基础上:

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

比较:

dbfiddle为PG 9.6这里
dbfiddle为第10页这里

澄清错误信息

手册:

对于INNEROUTER连接类型,必须指定一个连接条件,即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;

虽然这不是:

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