自从Postgres具备进行LATERAL连接的能力以来,我一直在阅读它,因为我目前为团队执行复杂的数据转储,其中包含许多效率低下的子查询,这些查询使整个查询花费了四分钟或更长时间。
LATERAL
我知道LATERAL联接可能会为我提供帮助,但是即使从Heap Analytics中阅读了类似这样的文章,我仍然不太了解。
联接的用例是LATERAL什么?LATERAL联接和子查询之间有什么区别?
该功能是PostgreSQL 9.3中引入的。 引用手册:
出现的子查询FROM之前可以带有关键字 LATERAL。这使他们可以引用前面的FROM项目提供的列 。(没有LATERAL,每个子查询都是独立评估的,因此不能交叉引用任何其他FROM项目。) 出现的表函数FROM也可以在关键字之后LATERAL,但是对于函数,关键字是可选的;例如:FROM在任何情况下,函数的参数都可以包含对前面各项提供的列的引用。
出现的子查询FROM之前可以带有关键字 LATERAL。这使他们可以引用前面的FROM项目提供的列 。(没有LATERAL,每个子查询都是独立评估的,因此不能交叉引用任何其他FROM项目。)
FROM
出现的表函数FROM也可以在关键字之后LATERAL,但是对于函数,关键字是可选的;例如:FROM在任何情况下,函数的参数都可以包含对前面各项提供的列的引用。
此处提供了基本代码示例。
甲LATERAL联接更像是一个相关子查询,而不是一个简单的子查询,在该表达式的右侧LATERAL连接中一次左的它的每一行评价- 就像一个 相关 子查询-而平原子查询(表表达式) 一次 只要。(不过,查询计划器可以通过其中一种方法来优化性能。)
有 是 事,一个LATERAL连接可以做,但一(相关的)子查询不能(容易)。相关的子查询只能返回一个值,不能返回多列,不能返回多行- 裸函数调用(如果结果行返回多行,则结果行相乘)除外。但是,即使某些特定的集合返回函数也只能在该FROM子句中使用。与unnest()Postgres 9.4或更高版本中的多个参数一样。手册:
unnest()
这仅在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 [, ... ] ):
,
CROSS JOIN
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页这里
手册:
对于INNER和OUTER连接类型,必须指定一个连接条件,即NATURAL、、ON join_condition 或USING( _ join_column_ [,…])中的一个。含义见下文。 对于CROSS JOIN,这些子句都不会出现。
INNER
OUTER
NATURAL
ON
USING
因此,这两个查询是有效的(即使不是特别有用):
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;~~