Det första problemet i ditt testscenario är att tabellen inte har något användbart index på firstname
. Det andra är att tabellen är tom.
Från Key-Range Locking i BOL
Det finns inget lämpligt index för att ta RangeS-S
låser så för att garantera serialiserbar semantik måste SQL Server låsa hela tabellen.
Om du försöker lägga till ett klustrat index i tabellen i kolumnen för förnamn enligt nedan och upprepa experimentet ...
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
... du kommer att upptäcka att du fortfarande är blockerad!
Trots att ett lämpligt index nu finns och genomförandeplanen visar att det söks in för att tillfredsställa frågan.
Du kan se varför genom att köra följande
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
Retur
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server tar inte bara ut ett intervalllås på exakt det intervall du anger i din fråga.
För ett likhetspredikat på ett unikt index om det finns en matchande nyckel kommer det bara att ta ett vanligt lås snarare än någon typ av intervalllås alls.
För ett icke unikt sökpredikat tar den ut lås på alla matchande nycklar inom intervallet plus den "nästa" i slutet av intervallet (eller på ffffffffffff
för att representera oändligheten om det inte finns någon "nästa" nyckel). Även raderade "ghost"-poster
kan användas i detta område med nyckellåsning.
Som beskrivs här för ett likhetspredikat på antingen ett unikt eller icke unikt index
Så med en tom tabell är SELECT
slutar fortfarande med att låsa hela indexet. Du måste också tidigare ha infogat en rad mellan abc
och lmn
och sedan skulle din insättning lyckas.
insert into dummy values('def', 'def')