web-dev-qa-db-fra.com

Pourquoi ce verrou RX-X n'apparaît-il pas dans les événements étendus?

Le problème

J'ai une paire de requêtes qui, sous isolement sérialisable, provoquent un verrouillage RX-X. Cependant, lorsque j'utilise des événements étendus pour regarder l'acquisition de verrouillage, l'acquisition de verrouillage RX-X n'apparaît jamais, elle est uniquement publiée. D'où est ce que ça vient?

Le Repro

Voici ma table:

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

Voici mon lot de problèmes:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

INSERT dbo.LockTest
VALUES ('bleh')

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

--ROLLBACK

Je vérifie les verrous détenus par cette session et vois 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

Mais j'ai également un événement étendu sur lock_acquired et lock_released. Je le filtre sur l'id_object_id associé approprié ... il n'y a pas de RX-X.

Extended Event output

Après avoir exécuté la restauration, je vois RX-X (LAST_MODE) publié, même s'il n'a jamais été acquis.

LAST_MODE

Ce que j'ai essayé

  • J'ai regardé tous les verrous dans les événements étendus - pas de filtrage. Aucun verrou RX-X acquis.

  • J'ai aussi essayé Profiler: mêmes résultats (sauf bien sûr qu'il obtient le bon nom ... pas de "LAST_MODE").

  • J'ai exécuté le XE pour les escalades de verrous - il n'est pas là.

  • Il n'y a pas de XE spécifiquement pour les conversions, mais j'ai pu confirmer qu'au moins la conversion de verrouillage U en X est capturée par lock_acquired

Il convient également de noter le RI-N qui est acquis mais jamais publié. Mon hypothèse actuelle est que le RX-X est un verrou de conversion, comme décrit ici . Il y a des verrous de plage de clés qui se chevauchent dans mon lot qui semblent devoir être qualifiés pour la conversion, mais le verrou RX-X n'est pas dans la table de conversion.

D'où vient ce verrou et pourquoi n'est-il pas récupéré par les événements étendus?

13
Forrest

L'insertion sur une seule ligne acquiert un verrou X (exclusif) sur la nouvelle ligne.

SELECT tente d'acquérir une plage partagée, une clé partagée (RangeS-S) fermer à clé.

Cette demande est signalée par le lock_acquired Événement étendu en mode = RS_S.

Il est signalé par la classe d'événements Profiler Lock:Acquired comme mode 13 (LCK_M_RS_S).

Le mode demandé est combiné avec le mode de verrouillage exclusif existant dans Lock::CalculateGrantMode dans sqlmin.dll. Il n'y a pas de mode combiné de plage partagée, clé exclusive (RangeS-X) donc le résultat du calcul est exclusif à la plage, exclusif à la clé (RangeX-X), qui se trouve être le mode 15.

Le calcul du mode d'autorisation ci-dessus est effectué juste avant que l'événement étendu soit généré par lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>. Néanmoins, le profileur et les événements étendus enregistrent le demandéRangeS-S mode, pas le mode de verrouillage résultant RangeX-X. Ceci est contraire à la limitation documentation , qui dit:

Mode | int | Mode résultant après l'acquisition du verrou.

La colonne mode de l'événement étendu ne contient aucune documentation et la description dans les métadonnées est vide. Peut-être que Microsoft eux-mêmes n'était même pas sûr du comportement.

J'ai souvent pensé qu'il serait plus utile que les événements de verrouillage signalent les modes demandé et résultant, mais ce n'est pas ce que nous avons. L'arrangement actuel rend pratiquement impossible le suivi et la correspondance de l'acquisition et de la libération des verrous.

Il y a peut-être une bonne raison de signaler les verrous de cette façon. S'il ne répond pas à vos besoins, vous pouvez ouvrir un dossier de support auprès de Microsoft ou créer un élément Azure Feedback.


LAST_MODE

Le mystérieux LAST_MODE est quelque chose qu'Erik Darling a remarqué avant . C'est le plus haut map_key valeur dans la liste des modes de verrouillage exposés par 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 structure de la mémoire accessible via le DMV (en utilisant sqlmin!CMapValuesTable) est stocké à partir de l'adresse sqlmin!XeSqlPkg::g_lock_mode. Chaque entrée de 16 octets dans la structure contient le map_key et un pointeur sur la chaîne renvoyée par map_value par le streaming TVF.

Les chaînes sont stockées exactement comme indiqué dans le tableau ci-dessus (mais pas dans cet ordre). Il semble que ce soit une erreur que l'entrée 21 ait un map_value de "LAST_MODE" au lieu du "RX_X" attendu. Erik Darling a a signalé le problème sur Azure Feedback .

12
Paul White 9