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

标签 sql postgresql join subquery lateral-join

自从 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 word LATERAL. This allows them to reference columns provided by preceding FROM items. (Without LATERAL, each subquery is evaluated independently and so cannot cross-reference any other FROM item.)

Table functions appearing in FROM can also be preceded by the key word LATERAL, but for functions the key word is optional; the function's arguments can contain references to columns provided by preceding FROM 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

澄清错误信息

The manual:

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 <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;

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

关于sql - PostgreSQL 中的 LATERAL JOIN 和子查询有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28550679/

相关文章:

mysql - 计算项目并显示它们

java - 如何解决 hsqldb 中的 SQLSyntaxErrorException?

sql - 无法从 postgres 中的 UPDATE RETURNING 子句中选择

python - 注释相关模型中注释值的总和

sql - 每周总计唯一序列号

mysql - 选择高级方式的位置

java - 使用最新版本时 upsert 出现语法错误

mysql - Mysql 创建一行具有相同 id 的数据

mysql - 为什么 CodeIgniter Active Record 和 phpMyAdmin 给出不同的结果?

sql - 与独特情侣有很多关系