Le premier problème dans votre scénario de test est que la table n'a pas d'index utile sur firstname
. La seconde est que la table est vide.
À partir de Verrouillage de plage de clés en BOL
Il n'y a pas d'index approprié pour prendre RangeS-S
se verrouille afin de garantir une sémantique sérialisable, SQL Server doit verrouiller toute la table.
Si vous essayez d'ajouter un index clusterisé sur la table sur la colonne du prénom comme ci-dessous et répétez l'expérience...
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
... vous constaterez que vous êtes toujours bloqué !
Malgré le fait qu'un index approprié existe maintenant et que le plan d'exécution montre qu'il est recherché pour satisfaire la requête.
Vous pouvez voir pourquoi en exécutant ce qui suit
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
SELECT *
FROM dummy
WHERE firstname = 'abc'
SELECT resource_type,
resource_description,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
COMMIT
Retours
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server ne prend pas simplement un verrou de plage sur exactement la plage que vous spécifiez dans votre requête.
Pour un prédicat d'égalité sur un index unique, s'il existe une clé correspondante, il prendra simplement un verrou normal plutôt que n'importe quel type de verrou de plage.
Pour un prédicat de recherche non unique, il supprime les verrous sur toutes les clés correspondantes dans la plage plus la "suivante" à la fin de la plage (ou sur ffffffffffff
pour représenter l'infini s'il n'existe pas de clé "suivante"). Même les enregistrements "fantômes" supprimés
peut être utilisé dans cette gamme de verrouillage à clé.
Comme décrit ici pour un prédicat d'égalité sur un index unique ou non unique
Donc avec une table vide le SELECT
finit toujours par verrouiller l'index entier. Vous devez également avoir préalablement inséré une ligne entre abc
et lmn
et alors votre insertion réussirait.
insert into dummy values('def', 'def')