Perché questo blocco RX-X non viene visualizzato in Eventi estesi?


13

Il problema

Ho un paio di query che, in isolamento serializzabile, causano un blocco RX-X. Tuttavia, quando utilizzo gli eventi estesi per guardare l'acquisizione del blocco, l'acquisizione del blocco RX-X non viene mai visualizzata, viene solo rilasciata. Da dove proviene?

The Repro

Ecco il mio tavolo:

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')

Ecco il mio problema batch:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

INSERT dbo.LockTest
VALUES ('bleh')

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

--ROLLBACK

Controllo i blocchi mantenuti da questa sessione e vedo 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

Ma ho anche un evento esteso su lock_acquirede lock_released. Lo filtro sull'appropriato associate_object_id ... non c'è RX-X.

Uscita evento estesa

Dopo aver eseguito il rollback, vedo RX-X (LAST_MODE) rilasciato, anche se non è mai stato acquisito.

LAST_MODE

Quello che ho provato

  • Ho esaminato tutti i blocchi in Eventi estesi - nessun filtro. Nessun blocco RX-X acquisito.

  • Ho anche provato Profiler: stessi risultati (tranne ovviamente ottiene il nome giusto ... no "LAST_MODE").

  • Ho eseguito l'XE per le escalation dei blocchi - non è lì.

  • Non esiste XE specifico per le conversioni, ma sono stato in grado di confermare che almeno la conversione del blocco da U a X è stata acquisita lock_acquired

Da notare anche il RI-N che viene acquisito ma mai rilasciato. La mia attuale ipotesi è che l'RX-X sia un blocco di conversione, come descritto qui . Nel mio batch sono presenti blocchi sovrapposti di intervalli di chiavi che sembrano idonei per la conversione, ma il blocco RX-X non si trova nella tabella di conversione.

Da dove proviene questo lucchetto e perché non viene raccolto da Extended Events?

Risposte:


12

L'inserto a riga singola acquisisce un Xblocco (esclusivo) sulla nuova riga.

I SELECTtentativi di acquisire un RangeS-Sblocco condiviso ( ) condiviso da chiave.

Questa richiesta viene segnalata lock_acquireddall'evento esteso come mode = RS_S.

Viene segnalato dalla classe di eventi Profiler Lock:Acquiredcome modalità 13 ( LCK_M_RS_S).

La modalità richiesta è combinata con quella esistente modalità di blocco esclusivoLock::CalculateGrantMode in sqlmin.dll. Non esiste una modalità combinata di intervallo condiviso, chiave esclusiva ( RangeS-X), quindi il risultato del calcolo è intervallo esclusivo, chiave esclusiva ( RangeX-X), che risulta essere la modalità 15.

Il calcolo della modalità di concessione sopra viene eseguito appena prima che l'evento esteso venga generato da lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>. Tuttavia, sia Profiler che Extended Events registrano la richiesta RangeS-S modalità , non la modalità di blocco risultante RangeX-X. Questo è contrario alla documentazione limitata , che dice:

Modalità | int | Modalità risultante dopo l'acquisizione del blocco.

La colonna modalità dell'evento esteso non ha alcuna documentazione e la descrizione nei metadati è vuota. Forse la stessa Microsoft non era nemmeno sicura del comportamento.

Ho spesso pensato che sarebbe stato più utile se gli eventi di blocco riportavano entrambi quelli richiesti modalità e risultanti , ma non è quello che abbiamo. La disposizione attuale rende praticamente impossibile tracciare e abbinare l'acquisizione e il rilascio del blocco.

Ci potrebbe essere un buon motivo per la segnalazione di serrature in questo modo. Se non soddisfa le tue esigenze, puoi aprire un caso di supporto con Microsoft o creare un elemento di feedback di Azure.


LAST_MODE

Il misterioso LAST_MODEè qualcosa che Erik Darling ha già sottolineato . È il map_keyvalore più alto nell'elenco delle modalità di blocco esposte da 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 ║
╚═════════╩═══════════╝

La struttura di memoria accessibile tramite DMV (utilizzando sqlmin!CMapValuesTable) viene memorizzata a partire dall'indirizzo sqlmin!XeSqlPkg::g_lock_mode. Ogni voce a 16 byte nella struttura contiene map_keye un puntatore alla stringa restituita come map_valuedallo streaming TVF.

Le stringhe sono memorizzate esattamente come mostrato nella tabella sopra (anche se non in quell'ordine). Sembra essere un errore che la voce 21 abbia un map_value"LAST_MODE" invece del previsto "RX_X". Erik Darling ha segnalato il problema su Azure Feedback .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.