web-dev-qa-db-ja.com

このRX-Xロックが拡張イベントに表示されないのはなぜですか?

問題

シリアル化可能な分離の下で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_acquiredlock_releasedにも拡張イベントがあります。適切なassociated_object_idでフィルタリングします... RX-Xはありません。

Extended Event output

ロールバックを実行した後、RX-X(LAST_MODE)が取得されなかったにもかかわらず、リリースされたことがわかります。

LAST_MODE

私が試したこと

  • 拡張イベントでallロックを確認しました-フィルタリングなし。 RX-Xロックは取得されませんでした。

  • 私はプロファイラーも試してみました:同じ結果です(もちろん、名前が正しくなります... "LAST_MODE"はありません)。

  • ロックのエスカレーションのためにXEを実行しました-ありません。

  • 変換専用のXEはありませんが、少なくともUからXへのロック変換がlock_acquiredによってキャプチャされていることを確認できました

また、RI-Nは取得されますが、リリースされることはありません。私の現在の仮説は、RX-Xが here で説明されているように変換ロックであるというものです。バッチにキー範囲ロックが重複しており、変換の対象となるように見えますが、RX-Xロックは変換テーブルにありません。

このロックはどこから来ているのですか、なぜ拡張イベントによって取得されないのですか?

13
Forrest

単一行の挿入により、新しい行のX(排他的)ロックが取得されます。

SELECTは、範囲共有、キー共有(RangeS-S)ロックの取得を試みます。

このリクエストは、lock_acquired拡張イベントによって、mode = RS_Sとして報告されます。

プロファイラーイベントクラスLock:Acquiredによって、モード13(LCK_M_RS_S)として報告されます。

要求されたモードは、Lock::CalculateGrantModesqlmin.dllの既存のexclusiveロックモードと組み合わされます。範囲共有、キー排他(RangeS-X)の組み合わせモードがないため、計算の結果は範囲排他、キー排他(RangeX-X)となり、モード15になります。

上記の許可モードの計算は、拡張イベントがlck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>によって生成される直前に実行されます。それにもかかわらず、プロファイラーと拡張イベントの両方がrequestedRangeS-Sモードをログに記録し、結果のロックモードRangeX-Xはログに記録しません。これは、制限された documentation に対抗します。

モード| int| ロックが取得された後の結果のモード。

拡張イベントのmode列にはドキュメントがまったくなく、メタデータの説明は空白です。おそらく、マイクロソフト自身もその振る舞いを確信していませんでした。

ロックイベントがrequestedresultingモードの両方を報告した方が便利だとよく思っていましたが、これは持ってる。現在の配置では、ロックの取得と解放を追跡して一致させることはほとんど不可能です。

mightこの方法でロックを報告するのには十分な理由があります。ニーズに合わない場合は、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 ║
╚═════════╩═══════════╝

sqlmin!CMapValuesTableを使用して)DMVを介してアクセスされるメモリ構造は、アドレスsqlmin!XeSqlPkg::g_lock_modeから格納されます。構造内の各16バイトエントリには、map_keyと、ストリーミングTVFによってmap_valueとして返される文字列へのポインターが含まれます。

文字列は、上記の表に示されているとおりに格納されます(ただし、この順序ではありません)。エントリ21のmap_valueが期待される「RX_X」ではなく「LAST_MODE」であると、エラーのようです。 Erik Darlingは Azureフィードバックで問題を報告しました を持っています。

12
Paul White 9