SQL Server:行順序
我們都知道一個簡單的語句如:
SELECT * FROM stuff;
不應產生有序的結果。然而,當我試圖證明這一點時,它總是以主鍵順序出現。
此外還有一個聲明,例如:
SELECT thing,whatever FROM stuff GROUP BY thing,whatever;
似乎總是按
GROUP BY
子句中的最後一個欄位對事物進行排序,這根本沒有幫助。問題是,在什麼情況下 SQL SERVER 會在未詢問的情況下對結果進行排序,我能做些什麼來阻止這種情況?
我試圖向我的學生證明,除非指定,否則訂單是不確定的,但這對我的情況沒有幫助。
我承認我正在處理一小組樣本數據。
謝謝
即使未詢問,SQL SERVER 在什麼情況下也會對結果進行排序?
如果檢索數據的訪問路徑恰好產生已排序的數據,例如按鍵順序進行索引掃描,則可能會發生這種情況。或者,如果計劃包含顯式排序,以便為需要此操作的操作員提供數據,例如合併連接或流聚合。如果沒有明確的
order by
順序,則無法保證,但 SQL Server 也不會竭盡全力阻止結果按順序輸出。我能做些什麼來阻止這種情況?
對於第一個查詢,如果 SQL Server 使用分配順序掃描,您可以看到不同的順序。
因此,請確保表的大小至少為 64 頁,並且分配順序與鍵順序不同,然後以未送出的讀取隔離級別執行查詢。
CREATE TABLE T ( X INT IDENTITY PRIMARY KEY, Y CHAR(4000) ); INSERT INTO T SELECT TOP 100 'A' FROM master..spt_values; /* Cause page splits so key order and allocation order differ and leaves one row per page so table is now > 64 pages*/ ALTER TABLE T ALTER COLUMN Y CHAR(4001); SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM T;
在採用表鎖的情況下,上述情況不需要讀取未送出,有一個提示,但不太明顯的方法是將上面的表定義更改為
CREATE TABLE T ( X INT IDENTITY PRIMARY KEY WITH(allow_row_locks = off, allow_page_locks = off), Y CHAR(4000) );
然後希望您無需更改隔離級別即可看到無序的結果。
對於第二個查詢,您需要雜湊聚合而不是流聚合。您可以通過查詢提示或不太明顯的計劃指南強制執行此操作,但如果與表的大小相比,不同的組相對較少,則更有可能有機地選擇。
Conor Cunningham(Microsoft 的 SQL Server 引擎軟體架構師)的這篇文章應該可以回答您的問題:
以下部分摘錄:
這裡的難點在於,任何外部使用者都沒有合理的方法知道計劃何時會改變。所有計劃的空間都很大,思考起來會讓人頭疼。如果有足夠多的參數更改,SQL Server 的優化器將更改計劃,即使對於簡單查詢也是如此。您可能很幸運並且沒有更改計劃,或者您可以不考慮這個問題並添加一個
ORDER BY
.$$ … $$ 在很多情況下,優化器中的計劃可能會發生變化——對於更複雜的查詢,可能有數千個或更多的計劃選擇,並且每個都有可能被選中的情況。對於這些計劃中的每一個,如果您不指定,該計劃的排序可能會有所不同。
所以,我今天的建議是:
如果您需要在查詢結果中排序,請輸入
ORDER BY
. 就是這麼簡單。其他任何事情都就像在沒有安全帶的情況下乘坐汽車一樣。