Sql-Server

為什麼在使用已送出讀快照隔離時需要 U 鎖

  • November 24, 2019

我認為自己是 Sql Server 鎖定的初學者。

我的理解是,在使用 RCSI 時,Sql Server 不需要發出 S 鎖,因為它使用行版本控制(在大多數情況下)。從http://technet.microsoft.com/en-us/library/jj856598(v=sql.110).aspx我們可以閱讀以下關於 U 鎖的內容:

用於可以更新的資源。防止在多個會話讀取、鎖定和稍後可能更新資源時發生的常見死鎖形式。

知道了這一點,為什麼Sql Server 需要發出U 鎖(使用RCSI 時)?在我看來,Sql Server 可以簡單地讀取行,並在必須執行更新時直接請求 X 鎖。

我一直在考慮這個問題的原因是因為我在 2 個會話更新同一個表時遇到了死鎖。像這樣的東西(為清楚起見而簡化):

第 1 節:

BEGIN TRAN
UPDATE t1 SET col1 = col1 + 100 WHERE col2 = value1
UPDATE t1 SET col1 = col1 + 100 WHERE col2 = value2
UPDATE t1 SET col1 = col1 + 100 WHERE col2 = value3

第 2 節:

BEGIN TRAN
UPDATE t1 SET col1 = col1 + 100 WHERE indexedcol = value4
UPDATE t1 SET col1 = col1 + 100 WHERE indexedcol = value5
UPDATE t1 SET col1 = col1 + 100 WHERE indexedcol = value6

根據我在 Profiler 鎖定報告中收集的資訊,兩個會話在表的某些行上都有 X 鎖定,並且正在請求對彼此的 X 鎖定行進行 U 鎖定 => 死鎖。但是,我知道每個並發會話總是會修改不同的行,因為值 X 在 2 個不同的並發會話中永遠不會相同。也就是說,如果這些會話能夠獲得他們請求的 U 鎖,sql server 將意識到無論如何都沒有必要升級 X 鎖。

總之,我覺得即使 U 鎖應該減少死鎖,但它們實際上在這裡創建了不必要的死鎖。

我知道它們對於其他隔離級別可能很有價值,但對於 RCSI,我不明白……

知道了這個,為什麼sql server 需要發出U 鎖(使用RCSI 時)?在我看來,sql server 可以簡單地讀取行,如果必須執行更新,則直接請求 X 鎖。

與 SI 不同,RCSI 不檢測更新衝突。如聯機叢書中所述,在 RCSI 下修改數據會讀取目前送出的數據,而不是可能過時的版本。(在沒有更新衝突檢測的情況下,根據過期數據執行更新可能會導致“失去更新”。)

獲取更新鎖是更新數據的非行版本控制查詢的正常行為。它可以防止轉換死鎖的常見原因,但它不能保證在所有情況下都避免死鎖,尤其是在使用不同的訪問路徑(索引)來限定要更改的行的情況下。

您可以在我的 SQLperformance.com 文章“讀取已送出快照隔離下的數據修改”中找到有關修改數據時 RCSI 的確切行為的更多詳細資訊。在文章“Read Committed Snapshot Isolation”中有更多關於 RCSI 的背景知識。

如果更新確實不相交,您可能會考慮使用快照隔離而不是 RCSI來執行更改(誠然,這在這方面具有復雜的行為)。

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