NOLOCK 提示更改返回記錄的順序
Client
表欄位上有一個聚集索引LastName
。當我簡單地從表中轉儲所有記錄時,它們按字母順序顯示,除非
(nolock)
在相關查詢中使用提示。該提示改變了記錄的順序。應該是?。我很肯定沒有其他會話與該表的更改有未結交易(至少sp_who2
沒有向我顯示任何內容)。如何解釋順序的差異?
從評論中提取的其他資訊:
- 沒有訂單。非聚集索引應該強制執行順序嗎?
- 即使使用指定聚集索引的索引提示,查詢仍會返回不同的順序。他們應該嗎?我想知道為什麼
nolock
在沒有明顯更改計劃的情況下更改返回記錄的順序。- 我對它們做了一個 WinDiff - 除了
$$ the $$
(nolock)
$$ query hint $$.
沒有子句的有序結果集的出現
ORDER BY
通常是由於掃描按索引順序檢索行所致。通常在預設隔離級別下選擇索引順序掃描的一個原因READ COMMITTED
是它減少了不必要的並發異常的機會,例如多次遇到同一行或完全跳過某些行。這在幾個地方都有詳細說明,包括關於隔離級別的系列文章。有了
NOLOCK
表提示,這種行為就放鬆了,對錶的訪問是在更寬容的READ UNCOMMITTED
隔離級別下進行的,它可能會按分配順序而不是索引順序掃描數據。如該連結中所述,是否使用分配順序或索引順序掃描的決定由儲存引擎決定。此選擇可能會在執行之間發生變化,而不會更改查詢計劃。這聽起來可能很抽象,但可以通過一些使用未記錄函式針對AdventureWorks2012 數據庫的查詢來更容易地展示。
USE AdventureWorks2012; GO -- Appears to be ordered by BusinessEntityID -- File:Page:Slot goes up and down several times -- Show physical locations with sys.fn_PhysLocFormatter (undocumented) SELECT P.BusinessEntityID, [(File:Page:Slot)] = sys.fn_PhysLocFormatter(%%physloc%%) FROM Person.Person AS P; -- Same query with TABLOCK or NOLOCK -- Allocation-order (IAM) scan -- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID SELECT P.BusinessEntityID, [(File:Page:Slot)] = sys.fn_PhysLocFormatter(%%physloc%%) FROM Person.Person AS P WITH (NOLOCK);
這些查詢是從Paul White那裡借來的,稍作修改。
最後,為了清楚起見,這個答案是關於有序結果集的*外觀。*沒有頂級的
ORDER BY
.分配順序掃描可能發生在各種其他情況下,例如獲取表級鎖或數據庫處於只讀模式時。並行性也會影響數據返回的順序。關鍵是,如果沒有
ORDER BY
,返回的順序數據可能會隨著時間的推移而變化。
當我簡單地從表中轉儲所有記錄時
…那麼你不應該期待任何訂單。事實上,多次執行相同的查詢可能會以不同的順序返回而不會發出警告。原因是您的兩個查詢 - 最有可能是因為不同的查詢文本而不是因為提示而成為“不同”查詢 - 具有不同的執行計劃(並且差異可能是微妙的,例如看起來相同的迭代器兩個計劃,但
ordered: true
只有一個;或者估計行數大不相同,因為一個是在重大數據更改之前編譯的)。正如詹姆斯在他的回答中正確概述的那樣,也可能正在進行分配訂單掃描。在任何情況下,由於您正在執行不帶 的查詢
ORDER BY
,SQL Server 會推斷您不關心順序,因此會開始並確定返回行的最有效方式(如果您不關心順序,則它不關心順序) )。讓我說得很清楚:
如果您想要或期望某個順序,請添加 ORDER BY 子句
這之前出現過:
我在部落格上寫過:
- 要改掉的壞習慣:依賴未記錄的行為(因為您在文件中的哪裡可以找到關於如何期望訂購“簡單表轉儲”的任何定義?)
- T-SQL 星期二 #56:SQL Server 假設(參見 #3)
這是後者的引述,重申了我所說的,以解決您關於使用索引提示而不是
ORDER BY
子句的評論:即使在提示索引的情況下,也會使用索引(如果可能,在大多數情況下會出錯),但僅僅因為使用了索引並不意味著結果將按中的鍵排序返回那個索引。您仍然需要
ORDER BY
確保按索引鍵排序。Conor Cunningham - 一個非常聰明的人,直接負責 SQL Server 在為您處理查詢時所做的大部分工作 - 也在這裡發表了部落格:
ORDER BY
在抱怨不同或意外的排序之前,請先閱讀一些內容,然後在您的查詢中添加一個子句。