Die Antwort von Justin Grant erklärt, was die LOCK_ESCALATION
Einstellung im Allgemeinen bewirkt, übersieht jedoch ein wichtiges Detail und erklärt nicht, warum SSMS den Code generiert, der sie festlegt. Insbesondere sieht es sehr seltsam aus, dass das LOCK_ESCALATION
als letzte Anweisung im Skript gesetzt ist.
Ich habe nur wenige Tests durchgeführt und hier ist mein Verständnis dafür, was hier passiert.
Kurzfassung
Die ALTER TABLE
Anweisung, die implizit eine Spalte hinzufügt, löscht oder ändert, erfordert eine SCH-M-Sperre (Schema Modify) für die Tabelle, die nichts mit der LOCK_ESCALATION
Einstellung einer Tabelle zu tun hat . LOCK_ESCALATION
wirkt sich das Verhalten während der DML - Anweisungen Sperren ( INSERT
, UPDATE
, DELETE
, etc.), nicht während der DDL - Anweisungen ( ALTER
). Die SCH-M-Sperre ist immer eine Sperre des gesamten Datenbankobjekts, in diesem Beispiel der Tabelle.
Dies ist wahrscheinlich, woher die Verwirrung kommt.
SSMS fügt die ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
Anweisung in allen Fällen zu seinem Skript hinzu , auch wenn sie nicht benötigt wird. In den Fällen , wenn diese Anweisung benötigt wird, wird es hinzugefügt , um die aktuelle Einstellung der Tabelle zu erhalten, nicht um die Tabelle zu sperren in irgendeiner bestimmten Weise während der Änderung der Tabelle Schema , das in diesem Skript passiert.
Mit anderen Worten, die Tabelle wird bei der ersten ALTER TABLE ALTER COLUMN
Anweisung mit der SCH-M-Sperre gesperrt, während die gesamte Arbeit zum Ändern des Tabellenschemas erledigt ist. Die letzte ALTER TABLE SET LOCK_ESCALATION
Aussage hat keinen Einfluss darauf. Es wirkt sich nur Aussagen über zukünftige DML ( INSERT
, UPDATE
, DELETE
, etc.) für diese Tabelle.
Auf den ersten Blick sieht es so aus, als hätte SET LOCK_ESCALATION = TABLE
es etwas damit zu tun, dass wir die gesamte Tabelle ändern (wir ändern hier ihr Schema), aber es ist irreführend.
Lange Version
Wenn Sie die Tabelle in einigen Fällen ändern, generiert SSMS ein Skript, das die gesamte Tabelle neu erstellt, und in einigen einfacheren Fällen (z. B. Hinzufügen oder Löschen einer Spalte) erstellt das Skript die Tabelle nicht neu.
Nehmen wir diese Beispieltabelle als Beispiel:
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
Jede Tabelle verfügt über eine LOCK_ESCALATION
Einstellung, die TABLE
standardmäßig festgelegt ist. Lassen Sie es uns hier ändern:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Wenn ich nun versuche, den Col1
Typ im SSMS-Tabellen-Designer zu ändern, generiert SSMS ein Skript, das die gesamte Tabelle neu erstellt:
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
Sie können oben sehen, dass es LOCK_ESCALATION
für die neu erstellte Tabelle festgelegt wird. SSMS tut dies, um die aktuelle Einstellung der Tabelle beizubehalten. SSMS generiert diese Zeile, auch wenn der aktuelle Wert der Einstellung der Standardwert TABLE
ist. Nur um sicher und explizit zu sein und mögliche zukünftige Probleme zu vermeiden, wenn sich diese Standardeinstellung in Zukunft ändert, denke ich. Das macht Sinn.
In diesem Beispiel ist es wirklich erforderlich, die SET LOCK_ESCALATION
Anweisung zu generieren , da die Tabelle neu erstellt wird und ihre Einstellung beibehalten werden muss.
Wenn ich versuche, mithilfe des SSMS-Tabellen-Designers eine einfache Änderung an der Tabelle vorzunehmen, z. B. eine neue Spalte hinzuzufügen, generiert SSMS ein Skript, das die Tabelle nicht neu erstellt:
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
Wie Sie sehen können, wird die ALTER TABLE SET LOCK_ESCALATION
Anweisung trotzdem hinzugefügt , obwohl sie in diesem Fall überhaupt nicht benötigt wird. Die erste ALTER TABLE ... ADD
ändert die aktuelle Einstellung nicht. Ich denke, SSMS-Entwickler haben entschieden, dass es sich nicht lohnt, festzustellen, in welchen Fällen diese ALTER TABLE SET LOCK_ESCALATION
Anweisung redundant ist, und sie immer zu generieren, nur um sicher zu gehen. Es schadet nicht, diese Aussage jedes Mal hinzuzufügen.
Auch hier ist die tabellenweite LOCK_ESCALATION
Einstellung irrelevant, während sich das Tabellenschema über die ALTER TABLE
Anweisung ändert . LOCK_ESCALATION
Die Einstellung wirkt sich nur auf das Sperrverhalten von DML-Anweisungen aus, z UPDATE
.
Zum Schluss ein Zitat aus ALTER TABLE
, betonen Sie meins:
Die in ALTER TABLE angegebenen Änderungen werden sofort implementiert. Wenn die Änderungen Änderungen an den Zeilen in der Tabelle erfordern, aktualisiert ALTER TABLE die Zeilen. ALTER TABLE erhält eine SCH-M-Sperre (Schema Modify) für die Tabelle, um sicherzustellen, dass während der Änderung keine anderen Verbindungen auf die Metadaten für die Tabelle verweisen, mit Ausnahme von Online-Indexoperationen, die am Ende eine sehr kurze SCH-M-Sperre erfordern. Bei einer Operation ALTER TABLE… SWITCH wird die Sperre sowohl für die Quell- als auch für die Zieltabelle erfasst. Die an der Tabelle vorgenommenen Änderungen werden protokolliert und können vollständig wiederhergestellt werden. Änderungen, die sich auf alle Zeilen in sehr großen Tabellen auswirken, z. B. das Löschen einer Spalte oder das Hinzufügen einer NOT NULL-Spalte mit einem Standardwert in einigen Editionen von SQL Server, können lange dauern, bis viele Protokolldatensätze abgeschlossen und generiert sind. Diese ALTER TABLE-Anweisungen sollten mit der gleichen Sorgfalt ausgeführt werden wie alle INSERT-, UPDATE- oder DELETE-Anweisungen, die viele Zeilen betreffen.