UNION ALL 子句的结果是否始终按顺序附加?

Erw*_*ter 10 postgresql order-by union

根据标准 SQL UNION/UNION ALL不保证没有外部ORDER BY子句的任何特定排序顺序 - 就像 SQL 中几乎没有任何地方不保证排序顺序一样ORDER BY

然而,Postgres 对 的普通情况使用“附加”步骤UNION ALL,因此第一个分支的结果(即使在其分区中未排序)总是出现在下一个分支之前,等等。Postgres 只是按照给定的顺序附加每个分支的结果。这与以下LIMIT条款特别相关:

SELECT 1 FROM tbl  -- or any complex query
UNION ALL
SELECT 2
LIMIT  1
Run Code Online (Sandbox Code Playgroud)

显然这不适用于UNION(without ALL)。但除此之外,我从未见过 Postgres 无序返回,即上述查询中的“2”SELECT ,而第一个查询也会返回行。即使第一站的费用极其昂贵,也不会。

我过去曾对这种行为进行过查询。现在我遇到了一个说法, Postgres 可能会在这里返回无序的行,但没有实际证据证实。

当前的Postgres 手册对此事有这样的说法:

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

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

任何人都可以展示一个示例,其中行返回无序,破坏了UNION ALL子句的顺序?在任何版本的 Postgres 中。(即使最新版本是最有趣的。)

如果不是这样,是否有理由相信这可能会在未来版本中发生变化?

ORDER BY这不是当前的问题。问题是多个UNION ALL子句是否按给定序列返回行(beforeLIMIT可以启动并停止进一步的分支执行)。

ype*_*eᵀᴹ 15

最近在 pgsql-docs 邮件列表中有一个类似的问题,
澄清组合查询中的排序保证(或缺乏)

我试图了解组合查询(UNION/UNION ALL/...)的排序方面的保证(如果有的话)。从该消息1可以看出,UNION ALL 确实保留了操作数查询的顺序,而 UNION 则不然(大概 INTERSECT、INTERSECT ALL、EXCEPT 和 EXCEPT ALL 也不保留)。

文档[2]没有提到这一点,我建议添加一个注释来澄清这一点。

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

由于文档不提供任何保证。如果您想要有序输出,请使用 ORDER BY。

不,没有任何保证。只是 UNION ALL 今天以这种方式工作(保留子选择的顺序) - 我什至不确定这一点,它可能不会在所有情况下保留顺序,具有不同的索引或分区或并行计划等。无论如何,不​​能保证未来的行为不会因为规划器的改进而改变。

是的,那个。您今天可以获得 UNION ALL 的并行计划:

=# explain analyze select * from foo union all select * from foo;
                                                                 QUERY PLAN                                                            

--------------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=0.00..208552.05 rows=5120008 width=244) (actual time=0.652..390.135 rows=5120000 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Append  (cost=0.00..208552.05 rows=2133336 width=244) (actual time=0.021..228.848 rows=1706667 loops=3)
         ->  Parallel Seq Scan on foo  (cost=0.00..98942.68 rows=1066668 width=244) (actual time=0.453..78.084 rows=853333 loops=3)
         ->  Parallel Seq Scan on foo foo_1  (cost=0.00..98942.68 rows=1066668 width=244) (actual time=0.024..125.299 rows=1280000 loops=2)
 Planning Time: 0.094 ms
 Execution Time: 488.352 ms
Run Code Online (Sandbox Code Playgroud)

确实,在简单的非并行化情况下,我们将执行第一个查询,然后执行第二个查询,但 SQL 不保证这是真的,Postgres 也不保证。