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

2024-05-08

自从 PostgreSQL 推出以来,它具备了以下功能:LATERAL连接,我一直在阅读它,因为我目前为我的团队进行复杂的数据转储,其中有许多低效的子查询,使整个查询需要四分钟或更长时间。

我明白那个LATERALjoins 可能可以帮助我,但即使在阅读了类似的文章之后this one http://blog.heapanalytics.com/postgresqls-powerful-new-join-type-lateral/从堆分析来看,我仍然不太明白。

的用例是什么LATERAL加入?和有什么区别LATERAL连接和子查询?


What is a LATERAL join?

该功能是在 PostgreSQL 9.3 中引入的。手册 https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-LATERAL:

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

表函数出现在FROM也可以在键之前 单词LATERAL,但对于函数来说,关键字是可选的;这 函数的参数可以包含对以下提供的列的引用 前FROM任何情况下的物品。

那里给出了基本的代码示例。

更像是一个相关的子查询

A LATERALjoin 更像是相关子查询 https://en.wikipedia.org/wiki/Correlated_subquery,不是一个普通的子查询,在 a 右侧的表达式中LATERALjoin 对其左侧的每一行进行一次评估 - 就像相关的子查询 - 计算普通子查询(表表达式)时once仅有的。 (不过,查询规划器有办法优化两者的性能。)
相关答案与并排的代码示例,解决相同的问题:

  • 优化 GROUP BY 查询以检索每个用户的最新行 https://stackoverflow.com/questions/25536422/optimize-group-by-query-to-retrieve-latest-record-per-user/25536748#25536748

对于返回超过一列, a LATERALjoin 通常更简单、更干净、更快。
另外,请记住,相关子查询的等效项是LEFT JOIN LATERAL ... ON true:

  • 使用数组参数多次调用设置返回函数 https://stackoverflow.com/questions/26107915/call-a-set-returning-function-with-an-array-argument-multiple-times/26514968#26514968

子查询不能做的事情

There are的事情LATERALjoin 可以,但(相关的)子查询不能(轻松地)。相关子查询只能返回单个值,不能返回多列,也不能返回多行 - 裸函数调用除外(如果返回多行,则将结果行相乘)。但即使某些返回集合的函数也只允许在FROM条款。喜欢unnest()Postgres 9.4 或更高版本中具有多个参数。手册: https://www.postgresql.org/docs/current/functions-array.html#ARRAY-FUNCTIONS-TABLE

这只允许在FROM clause;

所以这可行,但不能(轻易)用子查询替换:

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 [, ... ] ):

  • 如何声明 set-returning-function 只允许出现在 FROM 子句中? https://dba.stackexchange.com/a/160310/3684

中的集合返回函数SELECT list

您还可以使用设置返回函数,例如unnest() in the SELECT直接列出来。这曾经在同一个函数中表现出令人惊讶的行为,并且有多个这样的函数SELECT列出 Postgres 9.6 之前的版本。但它最终被 Postgres 10 清理掉了 https://www.postgresql.org/docs/10/xfunc-sql.html#XFUNC-SQL-FUNCTIONS-RETURNING-SET现在是一个有效的替代方案(即使不是标准 SQL)。看:

  • SELECT 子句中多个返回集合的函数的预期行为是什么? https://stackoverflow.com/questions/39863505/what-is-the-expected-behaviour-for-multiple-set-returning-functions-in-select-cl/39864815#39864815

基于上面的例子:

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

比较:

9.6 页的小提琴 https://dbfiddle.uk/asUCZoT5
第 10 页的小提琴 https://dbfiddle.uk/C42oryLC

To note:中的集合返回函数(的组合)SELECT产生的列表no rows消除该行。在内部它翻译为CROSS JOIN LATERAL ROWS FROM ...,不至于LEFT JOIN LATERAL ... ON true!

第 16 页的小提琴 https://dbfiddle.uk/AeiIKq95展示差异。

澄清错误信息

手册: https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM

For the INNER and OUTER连接类型,连接条件必须是 指定,即恰好之一NATURAL, ON 加入条件, or USING (加入列[,...])。含义见下文。
For 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;
罢工>

这就是为什么安多玛尔的 https://stackoverflow.com/a/28551339/939860代码示例是正确的(CROSS JOIN不需要连接条件)并且Attila's https://stackoverflow.com/a/28550962/939860不是。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PostgreSQL 中的 LATERAL JOIN 和子查询有什么区别? 的相关文章

  • 如何将可视选择的文本通过管道传输到 UNIX 命令并将输出附加到 Vim 中的当前缓冲区

    使用 Vim 我尝试将在可视模式下选择的文本通过管道传输到 UNIX 命令 并将输出附加到当前文件的末尾 例如 假设我们有一个 SQL 命令 例如 SELECT FROM mytable 我想做如下的事情
  • 当sql连接中存在两个同名列时,如何从一个表列中获取值

    当我连接两个具有相同名称列的表时 我目前面临着尝试获取值的问题 例如 table1 date和table2 date 每个表中的日期不同 我将如何获取 日期 本例中的表1 我目前正在跑步 while row mysqliquery gt f
  • 拆分列中的字符串并在列中添加值

    我有一个包含几行数据的表 如下所示 16 W 2 Work ALBO 00 Proposal ALxO Amendement 1 20091022 signed pdf 17 W 2 Work ALBO 00 Proposal Level1
  • Mysql 检索所有有限制的行

    我想检索特定用户的所有行 限制为 0 x 所以我只是想问是否有任何方法可以检索 mysql 中的所有行 而不调用返回 x 的 count id 的方法 而不重载现有函数 该函数在查询中根本没有限制 与我们的 string Relace 功能
  • 将 UUID 存储为 base64 字符串

    我一直在尝试使用 UUID 作为数据库键 我希望占用尽可能少的字节数 同时仍然保持 UUID 表示形式的可读性 我认为我已经使用 base64 将其减少到 22 个字节 并删除了一些尾随的 这些 对于我的目的来说似乎没有必要存储 这种方法有
  • 插入触发器最终在分区表中插入重复行

    我有一个分区表 我认为 适当的INSERT触发器和一些限制 不知何故 INSERT语句为每个语句插入 2 行INSERT 一个用于父分区 一个用于相应的分区 设置简要如下 CREATE TABLE foo id SERIAL NOT NUL
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 用户登录时的 Postgresql 触发器

    我正在尝试找出一种方法来了解用户何时登录 Postgres 数据库 有没有办法定义用户登录数据库时触发的触发器 或者是否有一个表或系统视图在任何人登录数据库时都会更新 登录钩子 https github com splendiddata l
  • 是否有适用于所有数据库的标准sql

    如下所示 不同数据库的语法有所不同 是否存在适用于所有数据库的标准方法 有没有什么工具可以将任意sql转换为任意sql SQL Server 2005 CREATE TABLE Table01 Field01 int primary key
  • 了解 SSMS 2008 中关系的更新和删除规则

    当我们定义外键约束时 我对 SQL Server 2008 Management Studio 中的更新和删除规则的含义感到困惑 我也没有找到相关的帮助文档 例如F1帮助 这是屏幕快照 如果有人能描述它们的含义并推荐一些相关文档来阅读 我将
  • 如何从 PostgreSQL 中的时间戳列值提取一天中的时间(或小时)?

    我正在尝试从 PostgreSQL 中的 时间戳 列中提取一天中的时间 这是我的做法 但是 太糟糕了 知道如何做得更好吗 SELECT date part hour date demande text hours date part min
  • 当所有维度值都具有 100% 重要性时处理多对多维度

    我至少会尽力保持简洁 假设我们正在跟踪一段时间内的账户余额 所以我们的事实表将包含诸如 账户余额情况表 FK 账户ID FK 日期ID Balance 显然你有一个账户维度表 and a 日期维度表 所以现在我们可以轻松地过滤帐户或日期 或
  • PHP 通过 SSL 连接到 MS SQL

    我想要实现的目标非常简单 我想通过安全连接从 PHP 脚本连接到外部 MS SQL 数据库 然而 这已被证明是有问题的 到目前为止 经过三个小时的研究 我不知所措 客户端的平台是Ubuntu 这意味着我无法使用SQLSRV 安全连接已经在不
  • wal_keep_segments 为什么是最小值而不是最大值?

    根据docs http www postgresql org docs current static runtime config replication html wal keep segments integer 指定过去日志的最小数量
  • MySQL 查询到 CSV [重复]

    这个问题在这里已经有答案了 有没有一种简单的方法来运行MySQL查询来自linux命令行并以csv格式输出结果 这就是我现在正在做的事情 mysql u uid ppwd D dbname lt lt EOQ sed e s g tee l
  • MyBatis:在一个查询中通过注释收集

    我有一个 xml 映射器 一个选择映射器和一个结果映射器 它工作没有问题 但我想使用注释 我的映射器
  • 自加入表

    我有一张像这样的桌子 Employee name salary a 10000 b 20000 c 5000 d 40000 我想获取所有工资高于A工资的员工 我不想使用任何嵌套或子查询 在采访中被问及并暗示是使用自连接 我真的不知道如何实
  • 将表数据从一个 SQL Server 导出到另一台 SQL Server

    我有两个 SQL Server 都是 2005 版本 我想将多个表从一个表迁移到另一个表 我努力了 在源服务器上 我右键单击数据库 选择Tasks Generate scripts 问题是在下面Table View options没有Scr
  • MS ACCESS 计数/求和行数,不重复

    我有下表 我需要计算总行数而不包括任何重复记录 CustomerID test1 test1 test2 test3 test4 test4 如您所见 总行数为 6 但有两个 test1 和两个 test4 我希望查询返回 4 IOW 我想
  • 在 Oracle 行的多个列上使用透视

    我在 Oracle 表中有以下示例数据 tab1 我正在尝试将行转换为列 我知道如何在某一列上使用 Oracle 数据透视表 但是否可以将其应用于多个列 样本数据 Type weight height A 50 10 A 60 12 B 4

随机推荐