web-dev-qa-db-fra.com

Compatibilité des verrous RangeI-N de plage de clés dans SQL Server

documentation indique que le verrou RangeI-N (Insérer une plage, verrou de ressource nul; utilisé pour tester des plages avant d'insérer une nouvelle clé dans un index) est compatible avec lui-même (voir la matrice de compatibilité), donc même bien qu'une transaction ait obtenu un verrou RangeI-N sur une clé particulière, une autre transaction peut également obtenir un tel verrou.

Plus loin, il est dit que

Lors de l'insertion d'une valeur dans une transaction, la plage dans laquelle la valeur tombe ne doit pas être verrouillée pendant la durée de la transaction effectuant l'opération d'insertion. Le verrouillage de la valeur de clé insérée jusqu'à la fin de la transaction est suffisant pour maintenir la sérialisation. Par exemple, étant donné cette instruction INSERT:

INSÉRER LES VALEURS de ma table ("Dan");

Le verrou de plage de clés du mode RangeI-N est placé sur l'entrée d'index correspondant au nom David pour tester la plage. Si le verrou est accordé, Dan est inséré et un verrou exclusif (X) est placé sur la valeur Dan. Le verrouillage de plage de touches du mode RangeI-N est nécessaire uniquement pour tester la plage et n'est pas maintenu pendant la durée de la transaction effectuant l'opération d'insertion. D'autres transactions peuvent insérer ou supprimer des valeurs avant ou après la valeur insérée Dan. Cependant, toute transaction tentant de lire, d'insérer ou de supprimer la valeur Dan sera verrouillée jusqu'à ce que la transaction d'insertion soit validée ou annulée.

Citant un autre source - Microsoft SQL Server 2008 Internals: Transactions and Concurrency:

Par exemple, le verrou RangeIn-Null est acquis lorsque SQL Server tente d'insérer dans la plage entre les clés d'une session à l'aide de l'isolement sérialisable. Ce type de verrou n'est pas souvent vu car il est généralement très transitoire. Il est conservé uniquement jusqu'à ce que l'emplacement correct d'insertion soit trouvé, puis le verrou est converti en verrou X.

Ma compréhension est que ce type de verrou est en cours d'identification de la plage où la clé nouvellement insérée doit être placée (je suppose que c'est ce que signifie `` tester la plage ''). Après cela, le verrou est libéré, la nouvelle clé est insérée et un verrou X est placé dessus.

Cependant, je ne vois pas pourquoi deux verrous RangeI-N seraient compatibles l'un avec l'autre. Si les transactions A et B placent toutes les deux un verrou RangeI-N sur la même clé car elles veulent toutes deux insérer une nouvelle clé dans la plage et que la transaction A effectue l'insertion en premier, alors l'emplacement d'insertion de clé déterminé par B peut être déjà incorrect car les plages ont changé (A y a inséré une nouvelle valeur). Quelqu'un pourrait-il expliquer cela?

9
user4205580

Ma compréhension est que ce type de verrou est en cours d'identification de la plage où la clé nouvellement insérée doit être placée (je suppose que c'est ce que signifie `` tester la plage ''). Après cela, le verrou est libéré, la nouvelle clé est insérée et un verrou X est placé dessus.

RangeI-N lock est demandé pour tester que l'insertion dans la plage de clés n'interfère pas avec une autre transaction qui peut potentiellement effectuer une opération sérialisable incompatible avec l'insertion (comme la lecture par exemple).

Pendant l'insertion de l'enregistrement dans le moteur de base de données d'index, la page localise l'emplacement où la clé insérée doit être placée. Les verrous de page et de clé ne sont pas encore utilisés à ce stade, seuls les verrous. Une fois la page localisée, le moteur commence à acquérir les verrous nécessaires pour effectuer l'insertion de l'enregistrement dans la page. Ce sont IX verrou pour la page localisée, puis RangeI-N verrouiller la clé à côté de la clé insérée. Lors de l'acquisition de RangeI-N n'est pas maintenu et le verrou X suivant pour la clé insérée est demandé. Une fois les verrous nécessaires acquis, l'insertion de l'enregistrement se poursuit.

Disons que nous avons une table et des données

CREATE TABLE T
(
    K int NOT NULL,
    CONSTRAINT UQ_T UNIQUE CLUSTERED (K)
);

INSERT INTO T (K)
VALUES (1), (2), (9), (10);

Prenons le résultat de la requête suivante

SELECT K, %%lockres%% AS lockres
FROM T;

lequel est

K    lockres
---- ---------------
1    (8194443284a0)
2    (61a06abd401c)
9    (30b7763ed433)
10   (d08358b1108f)

(nous y ferons référence dans les choses qui suivent).

Ensuite, disons que nous avons une requête

SELECT COUNT(*)
FROM T
WHERE K BETWEEN 1 AND 9;

L'exécuter sous SERIALIZABLE le niveau d'isolement entraîne l'empreinte de verrouillage suivante

SELECT locking footprint

Pour protéger la plage de clés, le moteur de base de données verrouille chaque clé de cette plage avec RangeS-S fermer à clé. De plus, la clé à côté de la plage est verrouillée (cela est nécessaire pour l'index non unique, mais le moteur le fait également pour l'index unique). Dans ce cas, des verrous sont placés sur les ressources correspondant (selon le résultat de la requête prise précédemment) aux clés 1, 2, 9 et 10.

Insertion non simultanée dans la table

INSERT INTO T (K)
VALUES (3);

résultats à l'empreinte de verrouillage suivante

INSERT locking footprint

La clé 3 n'existe pas dans la table et le moteur de base de données demande donc RangeI-N verrouiller la ressource (30b7763ed433) correspondant à la clé 9, qui est actuellement à côté de 3. Acquérir RangeI-N signifie qu'aucune activité sérialisable incompatible n'est effectuée, donc le moteur continue et acquiert X verrou sur la ressource (98ec012aa510) correspondant à la clé 3. Ensuite, l'insertion se produit et les verrous sont libérés. Notez qu'il n'y a pas de version de RangeI-N fermer à clé.

L'exécution au-dessus de SELECT et INSERT simultanément entraîne INSERT à attendre que la transaction effectuée sérialisable SELECT soit active

SELECT and INSERT concurrency

à cause de RangeI-N incompatibilité avec RangeS-S. Dès que la transaction effectuée SELECT se termine INSERT se poursuivra.

C'est ce que signifie "tester la plage".


Cependant, je ne vois pas pourquoi deux verrous RangeI-N seraient compatibles l'un avec l'autre.

RangeI-N la compatibilité des verrous est bonne, car elle permet des insertions simultanées dans la plage de clés.

Imaginez que nous faisons

INSERT INTO T (K)
VALUES (4);

et

INSERT INTO T (K)
VALUES (6);

simultanément.

Il peut arriver qu'à un certain moment, les deux instructions acquièrent RangeI-N sur la ressource (30b7763ed433) correspondant à la clé 9. Mais c'est très bien, car la concurrence est alors contrôlée par X sur les touches et par page se verrouillent plus loin.

4
i-one