Postgresql

UNION ALL 子句的結果是否總是按順序附加?

  • September 14, 2022

根據標準 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

顯然,這不適用於UNION(沒有ALL)。但除此之外,我從未見過 Postgres 亂序返回,即上述查詢中的*“2”*SELECT ,而第一個也會返回行。即使第一站非常昂貴,也不是。

我過去曾基於此行為的查詢。現在我遇到了一個說法,Postgres 可能會在這裡返回亂序的行,但沒有得到實際證據的證實。

目前的Postgres 手冊對此事有這樣的說法:

UNION有效地將結果附加到***query2結果query1***(儘管不能保證這是實際返回行的順序)。此外,它從結果中消除重複行,與使用 , 的方式 DISTINCT相同UNION ALL

這很不清楚。引用的順序是否適用於SELECT子句列表,或每個子句中的行,還是僅適用於返回的集合?此外,UNION ALL僅在第二句中提及,因此尚不清楚最重要的第一句是否應該適用於UNION ALL

任何人都可以舉一個例子,其中行被亂序返回,破壞了UNION ALL子句的順序?在任何版本的 Postgres 中。(即使最新版本最有趣。)

如果不是這樣,是否有理由相信這可能會在未來的版本中發生變化?

ORDER BY不是這裡的直接問題。問題是多個UNION ALL子句是否返回給定序列中的行(之前LIMIT可以啟動並阻止進一步的分支執行)。

最近在 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

確實,在簡單的非並行化情況下,我們將執行第一個查詢然後執行第二個查詢,但 SQL 並沒有保證這是真的,Postgres 也沒有。

引用自:https://dba.stackexchange.com/questions/316818