UNION ALL 子句的結果是否總是按順序附加?
根據標準 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 也沒有。