頁面鎖定過多
有一個查詢:
SELECT entry_id FROM table_name WHERE (path_id = 7 AND value_string = N'00020003-0004-0005-0006-000700080009' )
此查詢中的表包含數百萬條記錄。兩者
path_id
都有value_string
自己的非聚集索引。當我使用 SQL Server Profiler 使用
Lock:Acquired
事件跟踪此查詢時,我看到採取了三個 IS 頁面鎖:一個在包含value_string
“00020003-0004-0005-0006-000700080009”的頁面上,一個在包含path_id
as6
(這是驚人的),一個在包含path_id
as的頁面上7
(這是預期的)。我獲取有關頁面資訊的方式:
Lock:Acquired
有一個TextData
包含文本的欄位,例如1:87032
; 我接受並執行DBCC PAGE ('mc33', 1, 87032, 3)
然後我得到這樣的輸出:
問題是:如果查詢只對 sevens 感興趣,為什麼引擎會在只包含 sixes 的頁面上放置 IS 鎖?當此查詢與某些插入並行執行時,這種“過度”鎖定會導致我們死鎖,我想知道如何擺脫這種鎖定。
定位一個值意味著從上層點錨點遍歷(這解釋了
6
es)。IS
在 read-commited 隔離下遍歷需要鎖。這既不“過分”也不出人意料。如果我冒昧地猜測一下,我會推測這path_id
是一個低選擇性值,並且該索引沒有太大幫助。你抱怨死鎖,我建議你相應地調查它們,從死鎖圖開始。
附帶說明一下,使用基於行版本控制的隔離級別可以緩解過度鎖定(當真正引起關注時) 。如果您對 B-Tree seek 如何實際工作的底層細節感興趣,請從事務處理:概念和技術開始
詳細一點:內頁將包含一個鍵和一個指向頁/槽的指針。這意味著“從指針開始的頁麵包含小於此鍵值的值”。Seek 將搜尋上頁,直到找到大於 seek-ed 值的第一個鍵。它跳轉到指針並從那裡遞歸地繼續。如果上面的頁面說“從第 148 頁開始,所有鍵都小於 8”,並且第 148 頁包含 6es,則 seek 將使用 6es 鎖定頁面。這裡沒有魔法精靈塵埃。鎖定大量 6es 清楚地表明該鍵的選擇性非常低:有許多行重複了小範圍的鍵值。