Perché UPDLOCK causa l'arresto (blocco) di SELECT?


13

Ho una selezione in SQL SERVER che blocca l'intera tabella.

Ecco lo script di installazione (assicurati di non sovrascrivere nulla)

USE [master]
GO

IF EXISTS(SELECT 1 FROM sys.databases d WHERE d.name = 'LockingTestDB')
DROP DATABASE LockingTestDB
GO

CREATE DATABASE LockingTestDB
GO

USE [LockingTestDB]
GO
IF EXISTS(SELECT 1 FROM sys.tables t WHERE t.name = 'LockingTestTable')
  DROP TABLE LockingTestTable
GO

CREATE TABLE LockingTestTable (
  Id int IDENTITY(1, 1),
  Name varchar(100),
  PRIMARY KEY CLUSTERED (Id)
)
GO

INSERT INTO LockingTestTable(Name) VALUES ('1')
INSERT INTO LockingTestTable(Name) VALUES ('2')
GO

Apri una nuova finestra di query ed esegui la seguente transazione (che contiene un'attesa):

USE [LockingTestDB]
GO

BEGIN TRANSACTION
  SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '1'
  WAITFOR DELAY '00:01:00'

COMMIT TRANSACTION
--ROLLBACK
GO

USE [master]
GO

E un altro che verrà eseguito (assicurati che funzionino contemporaneamente):

USE [LockingTestDB]
GO

SELECT * FROM LockingTestTable t WITH (UPDLOCK, ROWLOCK) WHERE t.Name = '2'

USE [master]
GO

Noterai che la seconda query verrà bloccata dalla prima. Arresta la prima query ed esegui il ROLLBACK e il secondo verrà completato.

Perché sta succedendo?

PS: l'aggiunta di un indice non cluster (con copertura completa) su Nome lo risolverà:

USE [LockingTestDB]
GO

CREATE NONCLUSTERED INDEX [IX_Name] ON [dbo].[LockingTestTable] 
(
  [Name] ASC
)
INCLUDE ( [Id]) WITH (STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Ancora perché?

Risposte:


19

Come documentato nella documentazione online , UPDLOCKaccetta i blocchi di aggiornamento e li mantiene fino alla fine della transazione.

Senza un indice per individuare le righe da bloccare, tutte le righe testate vengono bloccate e i blocchi su righe qualificanti vengono mantenuti fino al completamento della transazione.

La prima transazione contiene un blocco di aggiornamento sulla riga in cui name = 1. La seconda transazione viene bloccata quando tenta di acquisire un blocco di aggiornamento sulla stessa riga (per verificare se name = 2 per quella riga).

Con un indice, SQL Server è in grado di individuare e bloccare rapidamente solo le righe qualificate, quindi non si verificano conflitti.

È necessario rivedere il codice con un professionista del database qualificato per convalidare il motivo del suggerimento di blocco e assicurarsi che siano presenti indici appropriati.

Informazioni correlate: Modifiche dei dati in Isolamento istantanea di commit della lettura

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.