Sql-Server

為什麼這個 RX-X 鎖沒有出現在擴展事件中?

  • August 21, 2019

問題

我有一對查詢,在可序列化的隔離下,會導致 RX-X 鎖定。但是,當我使用擴展事件觀看鎖獲取時,RX-X 鎖獲取永遠不會出現,它只是被釋放。它從何而來?

複製品

這是我的桌子:

CREATE TABLE dbo.LockTest (
ID int identity,
Junk char(4)
)

CREATE CLUSTERED INDEX CX_LockTest --not unique!
ON dbo.LockTest(ID)

--preload some rows
INSERT dbo.LockTest
VALUES ('data'),('data'),('data')

這是我的問題批次:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

INSERT dbo.LockTest
VALUES ('bleh')

SELECT *
FROM dbo.LockTest
WHERE ID = SCOPE_IDENTITY()

--ROLLBACK

我檢查了這個會話持有的鎖,並查看了 RX-X:

SELECT resource_type, request_mode, request_status, resource_description
FROM sys.dm_tran_locks
WHERE request_session_id = 72 --change SPID!

dm_tran_locks

lock_acquired但我在和上也有一個擴展事件lock_released。我在適當的 associated_object_id 上對其進行過濾……沒有 RX-X。

擴展事件輸出

執行回滾後,我看到 RX-X (LAST_MODE) 已釋放,即使它從未被獲取。

LAST_MODE

我試過的

  • 我查看了擴展事件中的*所有鎖 - 沒有過濾。*未獲得 RX-X 鎖。
  • 我也嘗試了 Profiler: 相同的結果(當然除了它的名字是正確的……沒有“LAST_MODE”)。
  • 我執行 XE 進行鎖定升級 - 它不存在。
  • 沒有專門用於轉換的 XE,但我能夠確認至少 U 到 X 鎖定轉換是由lock_acquired

另外值得注意的是被收購但從未發布的 RI-N。我目前的假設是 RX-X 是轉換鎖,如此所述。我的批次中有重疊的鍵範圍鎖,看起來它們應該有資格進行轉換,但 RX-X 鎖不在轉換錶中。

這個鎖是從哪裡來的,為什麼不被擴展事件拾取?

單行插入獲取X新行上的(獨占)鎖。

SELECT嘗試獲取範圍共享的密鑰共享 ( )RangeS-S鎖。

此請求由lock_acquired擴展事件報告為 mode = RS_S

Profiler 事件類將其報告Lock:Acquired為模式 13 ( LCK_M_RS_S)。

請求的模式與 in中現有的獨占鎖模式相結合。沒有範圍共享,鍵獨占()的組合模式,因此計算的結果是范圍獨占,鍵獨占(),恰好是模式15。Lock::CalculateGrantMode``sqlmin.dll``RangeS-X``RangeX-X

上面的授權模式計算是在擴展事件生成之前執行的lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>。儘管如此,Profiler 和 Extended Events 都會記錄請求 RangeS-S的模式,而不是生成的鎖定模式RangeX-X這與有限的文件相反,它說:

模式 | 整數| 獲取鎖後的結果模式。

擴展事件的模式欄根本沒有文件,元數據中的描述是空白的。也許微軟自己甚至不確定這種行為。

我經常認為如果鎖定事件同時報告請求模式和結果模式會更有用,但這不是我們所擁有的。目前的安排使得幾乎不可能跟踪和匹配鎖的獲取和釋放。

以這種方式報告鎖可能有充分的理由。如果它不能滿足你的需求,你可以向 Microsoft 開一個支持案例,或者創建一個 Azure 回饋項。


LAST_MODE

神秘LAST_MODE是埃里克·達林(Erik Darling)以前說過的。它是map_key公開的鎖定模式列表中的最大值sys.dm_xe_map_values

SELECT
   DXMV.map_key,
   DXMV.map_value
FROM sys.dm_xe_map_values AS DXMV
WHERE 
   DXMV.[name] = N'lock_mode'
ORDER BY
   DXMV.map_key;
╔═════════╦═══════════╗
║ map_key ║ map_value ║
╠═════════╬═══════════╣
║       0 ║ NL        ║
║       1 ║ SCH_S     ║
║       2 ║ SCH_M     ║
║       3 ║ S         ║
║       4 ║ U         ║
║       5 ║ X         ║
║       6 ║ IS        ║
║       7 ║ IU        ║
║       8 ║ IX        ║
║       9 ║ SIU       ║
║      10 ║ SIX       ║
║      11 ║ UIX       ║
║      12 ║ BU        ║
║      13 ║ RS_S      ║
║      14 ║ RS_U      ║
║      15 ║ RI_NL     ║
║      16 ║ RI_S      ║
║      17 ║ RI_U      ║
║      18 ║ RI_X      ║
║      19 ║ RX_S      ║
║      20 ║ RX_U      ║
║      21 ║ LAST_MODE ║
╚═════════╩═══════════╝

通過 DMV 訪問的記憶體結構(使用sqlmin!CMapValuesTable)儲存在地址 開始sqlmin!XeSqlPkg::g_lock_mode。結構中的每個 16 字節條目都包含和指向流 TVFmap_key返回的字元串的指針。map_value

字元串完全按照上表所示儲存(儘管不是按該順序)。map_value條目 21 具有“LAST_MODE”而不是預期的“RX_X”似乎是一個錯誤。Erik Darling在 Azure 回饋上報告了該問題

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