Det første problem i dit testscenarie er, at tabellen ikke har noget nyttigt indeks på firstname
. Det andet er, at bordet er tomt.
Fra Key-Range Locking i BOL
Der er ikke noget passende indeks til at tage RangeS-S
låser på, så for at sikre serialiserbar semantik skal SQL Server låse hele tabellen.
Hvis du prøver at tilføje et klynget indeks på tabellen i kolonnen for fornavn som nedenfor og gentage eksperimentet ...
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
... du vil opdage, at du stadig er blokeret!
På trods af at der nu findes et passende indeks, og udførelsesplanen viser, at det er søgt ind for at tilfredsstille forespørgslen.
Du kan se hvorfor ved at køre følgende
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
Returnerer
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server udtager ikke bare en rækkeviddelås på præcis det område, du angiver i din forespørgsel.
For et lighedsprædikat på et unikt indeks, hvis der er en matchende nøgle, vil det bare tage en almindelig lås i stedet for en hvilken som helst type rækkelås overhovedet.
For et ikke-entydigt søgeprædikat udtager den låse på alle matchende nøgler inden for området plus den "næste" i slutningen af området (eller på ffffffffffff
for at repræsentere uendelighed, hvis der ikke eksisterer en "næste" nøgle). Selv slettede "ghost"-poster
kan bruges i dette område nøglelåsning.
Som beskrevet her for et lighedsprædikat på enten et unikt eller ikke-entydigt indeks
Så med en tom tabel er SELECT
stadig ender med at låse hele indekset. Du skal også tidligere have indsat en række mellem abc
og lmn
og så ville din indsættelse lykkes.
insert into dummy values('def', 'def')