Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Perché inserire il blocco dell'istruzione TSQL quando il livello di isolamento della transazione per un'altra transazione è serializzabile con un filtro non in conflitto?

Il primo problema nello scenario di test è che la tabella non ha un indice utile su firstname . La seconda è che il tavolo è vuoto.

Da Blocco dell'intervallo di chiavi in BOL

Non esiste un indice adatto per prendere RangeS-S si blocca in modo da garantire una semantica serializzabile SQL Server deve bloccare l'intera tabella.

Se provi ad aggiungere un indice cluster sulla tabella nella colonna del nome come di seguito e ripeti l'esperimento...

CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)

... scoprirai di essere ancora bloccato!

Nonostante il fatto che ora esista un indice adatto e il piano di esecuzione mostri che viene cercato per soddisfare la query.

Puoi capire perché eseguendo quanto segue

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 

Resi

+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE      |                      | S            |
| OBJECT        |                      | IS           |
| PAGE          | 1:198                | IS           |
| KEY           | (ffffffffffff)       | RangeS-S     |
+---------------+----------------------+--------------+

SQL Server non si limita a eliminare un blocco di intervallo esattamente sull'intervallo specificato nella query.

Per un predicato di uguaglianza su un indice univoco, se esiste una chiave corrispondente, richiederà semplicemente un blocco normale anziché qualsiasi tipo di blocco dell'intervallo.

Per un predicato di ricerca non univoco rimuove i blocchi su tutte le chiavi corrispondenti all'interno dell'intervallo più quella "successiva" alla fine dell'intervallo (o su ffffffffffff per rappresentare l'infinito se non esiste una chiave "successivo"). Anche i record "ghost" eliminati può essere utilizzato in questa gamma di chiusura a chiave.

Come descritto qui per un predicato di uguaglianza su un indice univoco o non univoco

Quindi con una tabella vuota il SELECT finisce comunque per bloccare l'intero indice. Dovresti anche aver precedentemente inserito una riga tra abc e lmn e poi il tuo inserimento avrà successo.

insert into dummy values('def', 'def')