Mysql

對於這個特定的冗餘派生表,是否真的有可能無法保證訂單?

  • October 5, 2020

我在與 Lukas Eder 的 Twitter 對話中偶然發現了這個問題。

儘管正確的行為是將 ORDER BY 子句應用於最外層查詢,因為在這裡,我們沒有在最外層查詢中使用 DISTINCT、GROUP BY、JOIN 或任何其他 WHERE 子句,為什麼 RDBMS 不只是通過傳入數據,因為它是由內部查詢排序的?

SELECT * 
FROM (
   SELECT * FROM table ORDER BY time DESC
) AS t

至少,在 PostgreSQL 上執行此範例時,您會為內部查詢和此派生表範例獲得相同的執行計劃,以及相同的結果集。

因此,我假設 Planner 將簡單地丟棄最外層的查詢,因為它是多餘的,或者只是傳遞來自內部表的結果。

有沒有人認為情況可能並非如此?

大多數數據庫都非常清楚ORDER BY子查詢中的 an 是:

  • 不允許:例如 SQL Server、Sybase SQL Anywhere(除非用TOPor補充OFFSET .. FETCH
  • OFFSET .. FETCH無意義:例如 PostgreSQL、DB2(同樣,除非用or補充LIMIT

這是 DB2 LUW 手冊中的一個範例(重點是我的)

子選擇中的 ORDER BY 子句不會影響查詢返回的行的順序。如果在最外層的全查詢中指定了 ORDER BY 子句,它只會影響返回的行的順序。

措辭非常明確,就像 PostgreSQL 的一樣

如果未選擇排序,則將按未指定的順序返回行。這種情況下的實際順序將取決於掃描和連接計劃類型以及磁碟上的順序,但不能依賴它。只有明確選擇了排序步驟,才能保證特定的輸出排序。

從這個規範中,可以看出ORDER BY派生表中的子句產生的任何排序僅僅是偶然的,並且可能巧合地匹配您的預期排序(在您的簡單範例中,它在大多數數據庫中都是如此),但是依賴它是不明智的這。

關於 DB2 的旁注:

特別是,DB2 有一個鮮為人知的特性,稱為ORDER BY ORDER OF <table-designator>,可以按如下方式使用:

SELECT C1 FROM
  (SELECT C1 FROM T1
     UNION
   SELECT C1 FROM T2
   ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

在這種特殊情況下,派生表的順序可以在最外層的 SELECT 中顯式重用

關於甲骨文的旁注:

多年來,Oracle 的一種做法是OFFSET使用 實現分頁,只有對派生表排序後ROWNUM才能合理計算:

SELECT *
FROM (
 SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
 FROM (
   SELECT * FROM table ORDER BY time DESC
 ) t
) t
WHERE rn BETWEEN 10 AND 20

可以合理地預期,至少在ROWNUM查詢中,未來的 Oracle 版本不會破壞這種行為,以免破壞幾乎所有遺留的 Oracle SQL,這些遺留 SQL 尚未遷移到更理想的和可讀的 SQL 標準OFFSET .. FETCH語法:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

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