La risposta di Justin Grant spiega quale LOCK_ESCALATION
impostazione 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_ESCALATION
sia 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 TABLE
istruzione 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_ESCALATION
impostazione di una tabella. LOCK_ESCALATION
colpisce 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 COLUMN
istruzione mentre viene svolto tutto il lavoro di modifica dello schema della tabella. L'ultima ALTER TABLE SET LOCK_ESCALATION
affermazione 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 = TABLE
abbia 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_ESCALATION
un'impostazione, che è impostata di TABLE
default. Cambiamolo qui:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Ora, se provo a cambiare il Col1
tipo 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_ESCALATION
per 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 TABLE
valore 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_ESCALATION
istruzione, 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_ESCALATION
dichiarazione, anche se in questo caso non è affatto necessaria. Il primo ALTER TABLE ... ADD
non 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_ESCALATION
affermazione è ridondante e generarla sempre, solo per sicurezza. Non vi è alcun danno nell'aggiungere questa affermazione ogni volta.
Ancora una volta, l' LOCK_ESCALATION
impostazione a livello di tabella è irrilevante mentre lo schema della tabella cambia tramite l' ALTER TABLE
istruzione. LOCK_ESCALATION
l'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.