Lock Escalation - Cosa sta succedendo qui?


138

Durante la modifica di una tabella (rimozione di una colonna) in SQL Server 2008, ho fatto clic sul pulsante Genera script di modifica e ho notato che lo script di modifica generato rilascia la colonna, dice "go" e quindi esegue un'istruzione ALTER TABLE aggiuntiva che sembra impostare l'escalation del blocco per la tabella su "TABELLA". Esempio:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

Dovrei anche notare che questa è l'ultima cosa che sta facendo lo script di modifica. Cosa sta facendo qui e perché imposta LOCK_ESCALATION su TABLE?

Risposte:


165

" Blocca escalation " è il modo in cui SQL gestisce il blocco per aggiornamenti di grandi dimensioni. Quando SQL cambierà molte righe, è più efficiente per il motore di database prendere meno blocchi più grandi (ad esempio l'intera tabella) invece di bloccare molte cose più piccole (ad esempio blocchi di righe).

Ma questo può essere problematico quando hai un tavolo enorme, perché bloccare un intero tavolo può bloccare altre query per molto tempo. Questo è il compromesso: molti blocchi di piccole granularità sono più lenti di un numero inferiore (o uno) di blocchi a grana grossa e avere più query che bloccano parti diverse di una tabella crea la possibilità di deadlock se un processo è in attesa su un altro.

Esiste un'opzione a livello di tabella LOCK_ESCALATION, nuova in SQL 2008, che consente il controllo dell'escalation dei blocchi. L'impostazione predefinita "TABELLA" consente ai blocchi di salire fino al livello della tabella. DISABLE impedisce l'escalation dei blocchi all'intera tabella nella maggior parte dei casi. AUTO consente i blocchi della tabella, tranne se la tabella è partizionata, nel qual caso i blocchi vengono eseguiti solo fino al livello di partizione. Vedi questo post sul blog per maggiori informazioni.

Ho il sospetto che l'IDE aggiunga questa impostazione quando si ricrea una tabella perché TABLE è l'impostazione predefinita in SQL 2008. Si noti che LOCK_ESCALATION non è supportato in SQL 2005, quindi sarà necessario rimuoverlo se si tenta di eseguire lo script su un Istanza del 2005. Inoltre, poiché TABELLA è l'impostazione predefinita, puoi rimuovere in sicurezza quella riga quando riesegui lo script.

Si noti inoltre che, in SQL 2005 prima che questa impostazione fosse presente, tutti i blocchi potevano passare a livello di tabella - in altre parole, "TABELLA" era l'unica impostazione su SQL 2005.



6
@dma_k: questa opzione non è rilevante CREATE TABLEperché la tabella non esiste ancora, quindi non c'è nulla da bloccare.
Justin Grant,

1
Ma perché l'istruzione LOCK_ESCALATION dopo l' istruzione ALTER TABLE iniziale nello script di modifica durante la progettazione di una tabella in SSMS? Sicuramente a quel punto il lavoro è già stato fatto. Non dovrebbe essere prima di cambiare la struttura del tavolo?
Ingegnere invertito,

2
@DaveBoltman - il SET fa parte dell'istruzione ALTER TABLE. Non è un'affermazione separata. Vedi docs.microsoft.com/en-us/sql/t-sql/statements/…
Justin Grant

2
JustinGrant, tuttavia, rimane la domanda di @DaveBoltman. Lo script che SSMS genera, per esempio, aggiungendo una nuova colonna ha due ALTER TABLEistruzioni separate . Prima ALTER TABLE ADD column, poi GO, poi secondo ALTER TABLE SET LOCK_ESCALATION=TABLE, poi secondo GO. Quindi, LOCK_ESCALATIONviene impostato dopo l'aggiunta della colonna. Qual è il punto di impostarlo dopo il fatto? Queste due ALTER TABLEistruzioni sono racchiuse in una transazione, ma la colonna viene comunque aggiunta prima dell'impostazione LOCK_ESCALATION. Penso che scaverò ancora un po 'e scriverò un'altra risposta.
Vladimir Baranov,

11

Puoi verificare se devi includere l'istruzione LOCK_ESCALATION nello script confrontando questo valore prima e dopo aver eseguito la parte principale dello script:

SELECT lock_escalation_desc FROM sys.tables WHERE name='yourtablename'

Nel mio caso, la modifica della tabella per eliminare o aggiungere un vincolo non sembra modificare questo valore.


11

La risposta di Justin Grant spiega quale LOCK_ESCALATIONimpostazione fa in generale, ma manca un dettaglio importante e non spiega perché SSMS genera il codice che lo imposta. In particolare, sembra molto strano che LOCK_ESCALATIONsia impostato come ultima affermazione nella sceneggiatura.

Ho fatto alcuni test ed ecco la mia comprensione di ciò che sta accadendo qui.

Versione breve

L' ALTER TABLEistruzione che aggiunge, elimina o altera implicitamente una colonna accetta un blocco di modifica dello schema (SCH-M) sulla tabella, che non ha nulla a che fare con l' LOCK_ESCALATIONimpostazione di una tabella. LOCK_ESCALATIONcolpisce bloccaggio comportamento durante le istruzioni DML ( INSERT, UPDATE, DELETE, ecc), non durante le istruzioni DDL ( ALTER). Il blocco SCH-M è sempre un blocco dell'intero oggetto del database, tabella in questo esempio.

Questo è probabilmente da dove viene la confusione.

SSMS aggiunge l' ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)istruzione al suo script in tutti i casi, anche quando non è necessaria. Nei casi in cui questa istruzione è necessaria, viene aggiunta per preservare l'impostazione corrente della tabella, non per bloccare la tabella in un modo specifico durante la modifica allo schema della tabella che si verifica in quello script.

In altre parole, la tabella viene bloccata con il blocco SCH-M sulla prima ALTER TABLE ALTER COLUMNistruzione mentre viene svolto tutto il lavoro di modifica dello schema della tabella. L'ultima ALTER TABLE SET LOCK_ESCALATIONaffermazione non la influenza. Essa colpisce solo le dichiarazioni futuro DML ( INSERT, UPDATE, DELETE, etc.) di quel tavolo.

A prima vista sembra che SET LOCK_ESCALATION = TABLEabbia a che fare con il fatto che stiamo cambiando l'intera tabella (qui stiamo modificando il suo schema), ma è fuorviante.

Versione lunga

Quando si modifica la tabella in alcuni casi, SSMS genera uno script che ricrea l'intera tabella e in alcuni casi più semplici (come l'aggiunta o il rilascio di una colonna), lo script non ricrea la tabella.

Prendiamo questa tabella di esempio come esempio:

CREATE TABLE [dbo].[Test](
    [ID] [int] NOT NULL,
    [Col1] [nvarchar](50) NOT NULL,
    [Col2] [int] NOT NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Ogni tabella ha LOCK_ESCALATIONun'impostazione, che è impostata di TABLEdefault. Cambiamolo qui:

ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)

Ora, se provo a cambiare il Col1tipo nel designer della tabella SSMS, SSMS genera uno script che ricrea l'intera tabella:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Test
    (
    ID int NOT NULL,
    Col1 nvarchar(10) NOT NULL,
    Col2 int NOT NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Test SET (LOCK_ESCALATION = DISABLE)
GO
IF EXISTS(SELECT * FROM dbo.Test)
     EXEC('INSERT INTO dbo.Tmp_Test (ID, Col1, Col2)
        SELECT ID, CONVERT(nvarchar(10), Col1), Col2 FROM dbo.Test WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Test
GO
EXECUTE sp_rename N'dbo.Tmp_Test', N'Test', 'OBJECT' 
GO
ALTER TABLE dbo.Test ADD CONSTRAINT
    PK_Test PRIMARY KEY CLUSTERED 
    (
    ID
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT

Si può vedere sopra che imposta LOCK_ESCALATIONper la tabella appena creata. SSMS lo fa per preservare l'impostazione corrente della tabella. SSMS genera questa riga, anche se il valore corrente dell'impostazione è il TABLEvalore predefinito . Giusto per essere sicuro ed esplicito e prevenire possibili problemi futuri se in futuro questo default cambia, immagino. Questo ha senso.

In questo esempio è davvero necessario generare l' SET LOCK_ESCALATIONistruzione, poiché la tabella viene creata di nuovo e la sua impostazione deve essere preservata.

Se provo a apportare una semplice modifica alla tabella utilizzando il designer di tabelle SSMS, ad esempio aggiungendo una nuova colonna, SSMS genera uno script che non ricrea la tabella:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Test ADD
    NewCol nchar(10) NULL
GO
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
GO
COMMIT

Come puoi vedere, aggiunge comunque la ALTER TABLE SET LOCK_ESCALATIONdichiarazione, anche se in questo caso non è affatto necessaria. Il primo ALTER TABLE ... ADDnon cambia l'impostazione corrente. Immagino che gli sviluppatori di SSMS abbiano deciso che non vale la pena provare a determinare in quali casi questa ALTER TABLE SET LOCK_ESCALATIONaffermazione è ridondante e generarla sempre, solo per sicurezza. Non vi è alcun danno nell'aggiungere questa affermazione ogni volta.

Ancora una volta, l' LOCK_ESCALATIONimpostazione a livello di tabella è irrilevante mentre lo schema della tabella cambia tramite l' ALTER TABLEistruzione. LOCK_ESCALATIONl'impostazione influenza solo il comportamento di blocco delle istruzioni DML, come UPDATE.

Infine, una citazione da ALTER TABLE, sottolinea il mio:

Le modifiche specificate in ALTER TABLE vengono implementate immediatamente. Se le modifiche richiedono modifiche delle righe nella tabella, ALTER TABLE aggiorna le righe. ALTER TABLE acquisisce un blocco di modifica dello schema (SCH-M) sulla tabella per assicurarsi che nessun'altra connessione faccia riferimento ai metadati della tabella durante la modifica, ad eccezione delle operazioni sugli indici online che richiedono un blocco SCH-M molto breve alla fine. In un'operazione ALTER TABLE ... SWITCH, il blocco viene acquisito su entrambe le tabelle di origine e destinazione. Le modifiche apportate alla tabella sono registrate e completamente recuperabili. Le modifiche che influiscono su tutte le righe di tabelle molto grandi, come il rilascio di una colonna o, in alcune edizioni di SQL Server, l'aggiunta di una colonna NOT NULL con un valore predefinito, possono richiedere molto tempo per completare e generare molti record di registro. Queste istruzioni ALTER TABLE devono essere eseguite con la stessa cura di qualsiasi istruzione INSERT, UPDATE o DELETE che interessa molte righe.

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.