Sql-Server-2012

NOLOCK 提示更改返回記錄的順序

  • May 7, 2020

Client表欄位上有一個聚集索引LastName

當我簡單地從表中轉儲所有記錄時,它們按字母順序顯示,除非(nolock)在相關查詢中使用提示。該提示改變了記錄的順序。應該是?。我很肯定沒有其他會話與該表的更改有未結交易(至少sp_who2沒有向我顯示任何內容)。

如何解釋順序的差異?

從評論中提取的其他資訊:

  1. 沒有訂單。非聚集索引應該強制執行順序嗎?
  2. 即使使用指定聚集索引的索引提示,查詢仍會返回不同的順序。他們應該嗎?我想知道為什麼nolock在沒有明顯更改計劃的情況下更改返回記錄的順序。
  3. 我對它們做了一個 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 子句

這之前出現過:

我在部落格上寫過:

這是後者的引述,重申了我所說的,以解決您關於使用索引提示而不是ORDER BY子句的評論:

即使在提示索引的情況下,也會使用索引(如果可能,在大多數情況下會出錯),但僅僅因為使用了索引並不意味著結果將按中的鍵排序返回那個索引。您仍然需要ORDER BY確保按索引鍵排序。

Conor Cunningham - 一個非常聰明的人,直接負責 SQL Server 在為您處理查詢時所做的大部分工作 - 也在這裡發表了部落格:

ORDER BY在抱怨不同或意外的排序之前,請先閱讀一些內容,然後在您的查詢中添加一個子句。

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