首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UNION ALL子句的结果是否总是按顺序追加?

UNION ALL子句的结果是否总是按顺序追加?
EN

Database Administration用户
提问于 2022-09-12 23:50:54
回答 2查看 2.8K关注 0票数 7

按照标准的SQL UNION / UNION ALL,如果没有外部ORDER BY子句,就不会保证任何特定的排序顺序--就像没有ORDER BY保证排序顺序的地方一样。

但是,Postgres对UNION ALL的普通情况使用一个“追加”步骤,因此第一个支腿的结果(即使在分区中没有排序)总是在下一个支路之前出现,等等。Postgres只是按给定的顺序追加来自每个支腿的结果。这与LIMIT条款特别相关:

代码语言:javascript
复制
SELECT 1 FROM tbl  -- or any complex query
UNION ALL
SELECT 2
LIMIT  1

显然,这不适用于UNION (没有ALL)。但除此之外,我从未见过Postgres按顺序返回,即从上述查询中返回“2”,而第一个SELECT也将返回行(S)。即使第一条腿非常昂贵,也不会。

我以前也有过基于这种行为的疑问。现在,我收到了一份索赔 Postgres可能会在这里不正常地返回行,但是没有实际的证据。

当前的Postgres手册在这个问题上有这样的说法:

UNION有效地将query2的结果附加到query1的结果(尽管不能保证这是实际返回行的顺序)。此外,它以与DISTINCT相同的方式从其结果中消除重复行,除非使用UNION ALL

这还不清楚。引用的命令是否适用于SELECT子句的列表,或每个子句中的行,还是仅适用于返回的集合?此外,UNION ALL仅在第二句中提到,因此尚不清楚是否最重要的第一句应该适用于UNION ALL .

有人能给我们举一个例子吗?在哪里,行被按顺序返回,打破了UNION ALL子句的顺序?任何版本的Postgres。(即使最新版本将是最有趣的。)

如果不是这样的话,是否有理由相信这种情况可能会在未来的版本中发生改变?

ORDER BY不是眼前的问题。问题是多个UNION ALL子句是否以给定的顺序返回行(在LIMIT可以启动并停止进一步的分支执行之前)。

EN

回答 2

Database Administration用户

回答已采纳

发布于 2022-09-13 11:11:39

最近在pgsql-docs邮件列表中也有类似的问题,

澄清合并查询(或缺少查询)中的排序保证

我试图理解--如果有的话--关于组合查询排序的保证(UNION/UNION ALL/.)。从这条消息1来看,UNION似乎确实保留了操作数查询的顺序,而UNION则没有(大概也不这样做)。文档2没有提到这一点,我建议添加一个说明来澄清这一点。

汤姆·莱恩(和其他人)回答说:

因为文件没有保证,所以没有保证。如果您想要有序输出,请使用ORDER。不,没有保证。只是UNION今天是这样工作的(保持子选择的顺序)--我甚至不确定,它可能不会在所有情况下都保持顺序,有不同的索引、分区或并行计划等等。无论如何,不能保证行为在未来不会因为计划者的改进而改变。是啊,那个。您今天可以为UNION获得一个并行化的计划:=#解释,分析select,select * from,union,all select* foo;查询计划PLAN(cost=0.00..208552.05 rows=5120008 width=244) (实际time=0.652..390.135 rows=5120000 loops=1)工人计划:2名工作人员启动:2 ->并行追加(cost=0.00..208552.05 rows=2133336 width=244) (实际time=0.021..228.848 rows=1706667 loops=3),->并行扫描对foo (cost=0.00..98942.68 rows=1066668 width=244) (实际time=0.453..78.084 rows=853333 loops=3) -> Parallel对foo foo_1 (cost=0.00..98942.68 loops=3)(实际on 20#)计划时间: 0.094 ms执行时间: 488.352 ms在简单的非并行化情况下,我们将执行第一个查询,然后再执行第二个查询,但是SQL并不保证这是真的,Postgres也是如此。

票数 12
EN

Database Administration用户

发布于 2022-09-13 21:54:15

已经确定,不能保证在下一个UNION ALL项的行之前返回来自第一个UNION ALL项的行。

干净的解决办法是不依赖从句的顺序。

替代品

对于上面所示的简单查询(不包括外部ORDER BYJOIN),在将Parallel Append添加到Postgres 11并行计划之前,都会观察到序列。仅仅因为Append是唯一的计划选项--即(是)以这种方式实现的。

在目前的Postgres 15中,只要Parallel Append不参与,它仍能正常工作--这只发生在大场景中。您可以通过禁用该选项来确保这一点。手册:

enable_parallel_append可用于禁用此功能。

您可以在本地设置此选项,甚至只是为了使当前事务能够快速地用以下方法修补旧代码:

代码语言:javascript
复制
SET LOCAL enable_parallel_append = off;

不要被这样一个临时的解决办法所困扰。最好正确地修复SQL代码。

适当方案

弗拉迪奇评论道:

...这里的问题是,如果您使用的是ORDER BY,您将失去“在接收到一定数量的行之前按特定顺序执行”的方便功能。除了按顺序执行多个查询(这可能效率较低,而且一般还需要动态SQL )之外,我看不到有任何其他方法可以做到这一点。

我能想到的下一个最好的事情是构建这个集合的PL/pgSQL函数。您可以使用GET DIAGNOSTICS检查每次查询后的结果行数,为下一个查询修改(减少) LIMIT,并在找到足够多时立即修改( RETURN )。可以在不使用动态SQL (因此不需要EXECUTE )的情况下完成,因为LIMIT接受参数。请参见:

更多的代码。更多的计划开销。但好的一面是:动态适应的LIMIT甚至可以为后续查询生成更好的查询计划。

另一个例子是,在循环中重复相同的查询,也不需要动态SQL:

为动态LIMIT编写代码示例,同时在循环中使用带有EXECUTE的动态SQL:

票数 4
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/316818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档