คำตอบโดย Justin Grant อธิบายถึงLOCK_ESCALATION
การตั้งค่าโดยทั่วไป แต่ขาดรายละเอียดที่สำคัญอย่างหนึ่งและไม่ได้อธิบายว่าเหตุใด SSMS จึงสร้างรหัสที่ตั้งค่าไว้ โดยเฉพาะอย่างยิ่งมันดูแปลกมากที่LOCK_ESCALATION
ตั้งค่าเป็นคำสั่งสุดท้ายในสคริปต์
ฉันทำการทดสอบไม่กี่ครั้งและนี่คือความเข้าใจของฉันเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่
เวอร์ชั่นสั้น
ALTER TABLE
งบที่เพิ่มหยดหรือ alters คอลัมน์โดยปริยายใช้เวลาปรับเปลี่ยนสคี (SCH-M) ล็อคบนโต๊ะซึ่งมีอะไรจะทำอย่างไรกับLOCK_ESCALATION
การตั้งค่าของตาราง LOCK_ESCALATION
ส่งผลกระทบต่อพฤติกรรมการล็อคในช่วงงบดราก้อน ( INSERT
, UPDATE
, DELETE
ฯลฯ ) ไม่ได้ในช่วงงบ DDL (ที่ALTER
) SCH-M lock เป็นการล็อกวัตถุฐานข้อมูลทั้งหมดเสมอตารางในตัวอย่างนี้
นี่อาจเป็นที่มาของความสับสน
SSMS จะเพิ่มALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
คำสั่งให้กับสคริปต์ในทุกกรณีแม้ว่าจะไม่จำเป็นก็ตาม ในกรณีที่จำเป็นต้องใช้คำสั่งนี้คำสั่งนี้จะถูกเพิ่มเพื่อรักษาการตั้งค่าปัจจุบันของตารางไม่ให้ล็อกตารางในลักษณะเฉพาะบางอย่างระหว่างการเปลี่ยนแปลงสคีมาของตารางที่เกิดขึ้นในสคริปต์นั้น
กล่าวอีกนัยหนึ่งตารางจะถูกล็อคด้วยการล็อก SCH-M ในALTER TABLE ALTER COLUMN
คำสั่งแรกในขณะที่งานทั้งหมดในการเปลี่ยนสคีมาของตารางเสร็จสิ้น ALTER TABLE SET LOCK_ESCALATION
คำสั่งสุดท้ายไม่มีผลกับมัน มันมีผลต่องบอนาคตดราก้อนเท่านั้น ( INSERT
, UPDATE
, DELETE
ฯลฯ ) สำหรับตารางที่
เมื่อมองแวบแรกดูเหมือนว่าSET LOCK_ESCALATION = TABLE
มีส่วนเกี่ยวข้องกับข้อเท็จจริงที่ว่าเรากำลังเปลี่ยนตารางทั้งหมด (เรากำลังแก้ไขสคีมาที่นี่) แต่มันทำให้เข้าใจผิด
เวอร์ชันยาว
เมื่อแก้ไขตารางในบางกรณี SSMS จะสร้างสคริปต์ที่สร้างใหม่ทั้งตารางและในบางกรณีที่ง่ายกว่านั้น (เช่นการเพิ่มหรือวางคอลัมน์) สคริปต์จะไม่สร้างตารางขึ้นมาใหม่
ลองใช้ตารางตัวอย่างนี้เป็นตัวอย่าง:
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
แต่ละตารางมีการLOCK_ESCALATION
ตั้งค่าซึ่งถูกตั้งค่าเป็นค่าTABLE
เริ่มต้น มาเปลี่ยนที่นี่:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
ตอนนี้ถ้าฉันพยายามเปลี่ยนCol1
ประเภทในตัวออกแบบตาราง SSMS SSMS จะสร้างสคริปต์ที่สร้างใหม่ทั้งตาราง:
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
คุณสามารถดูด้านบนว่ามันถูกตั้งค่าLOCK_ESCALATION
สำหรับตารางที่สร้างขึ้นใหม่ SSMS ทำเพื่อรักษาการตั้งค่าปัจจุบันของตาราง SSMS สร้างบรรทัดนี้แม้ว่าค่าปัจจุบันของการตั้งค่าจะเป็นค่าเริ่มต้นTABLE
ก็ตาม เพียงเพื่อความปลอดภัยและชัดเจนและป้องกันปัญหาในอนาคตที่อาจเกิดขึ้นหากในอนาคตค่าเริ่มต้นนี้เปลี่ยนแปลงไปฉันคิดว่า สิ่งนี้สมเหตุสมผล
ในตัวอย่างนี้จำเป็นอย่างยิ่งในการสร้างSET LOCK_ESCALATION
คำสั่งเนื่องจากตารางถูกสร้างขึ้นใหม่และต้องคงการตั้งค่าไว้
ถ้าฉันพยายามเปลี่ยนแปลงตารางโดยใช้ตัวออกแบบตาราง SSMS เช่นการเพิ่มคอลัมน์ใหม่ SSMS จะสร้างสคริปต์ที่ไม่ได้สร้างตารางขึ้นมาใหม่:
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
อย่างที่คุณเห็นมันยังคงเพิ่มALTER TABLE SET LOCK_ESCALATION
คำสั่งแม้ว่าในกรณีนี้จะไม่จำเป็นเลยก็ตาม อย่างแรกALTER TABLE ... ADD
ไม่เปลี่ยนการตั้งค่าปัจจุบัน ฉันเดาว่านักพัฒนา SSMS ตัดสินใจว่าไม่คุ้มค่ากับความพยายามที่จะพยายามพิจารณาว่าในกรณีใดที่ALTER TABLE SET LOCK_ESCALATION
คำสั่งนี้ซ้ำซ้อนและสร้างขึ้นเสมอเพื่อความปลอดภัย ไม่มีอันตรายใด ๆ ในการเพิ่มคำสั่งนี้ทุกครั้ง
อีกครั้งการLOCK_ESCALATION
ตั้งค่าทั้งตารางไม่เกี่ยวข้องในขณะที่สคีมาของตารางเปลี่ยนแปลงผ่านALTER TABLE
คำสั่ง การตั้งค่ามีผลกระทบเฉพาะพฤติกรรมการล็อคของงบดราก้อนเช่นLOCK_ESCALATION
UPDATE
ในที่สุดคำพูดจากALTER TABLE
เน้นฉัน:
การเปลี่ยนแปลงที่ระบุใน ALTER TABLE จะดำเนินการทันที หากการเปลี่ยนแปลงจำเป็นต้องมีการแก้ไขแถวในตาราง ALTER TABLE จะอัปเดตแถว ALTER TABLE รับการล็อกการแก้ไข schema (SCH-M) บนตารางเพื่อให้แน่ใจว่าไม่มีการเชื่อมต่ออื่น ๆ ที่อ้างอิงแม้แต่ข้อมูลเมตาสำหรับตารางในระหว่างการเปลี่ยนแปลงยกเว้นการดำเนินการดัชนีออนไลน์ที่ต้องใช้การล็อก SCH-M ที่สั้นมากในตอนท้าย ในการดำเนินการ ALTER TABLE … SWITCH การล็อกจะได้มาจากทั้งตารางต้นทางและตารางเป้าหมาย การแก้ไขที่ทำกับตารางจะถูกบันทึกและสามารถกู้คืนได้ทั้งหมด การเปลี่ยนแปลงที่มีผลต่อแถวทั้งหมดในตารางที่มีขนาดใหญ่มากเช่นการวางคอลัมน์หรือใน SQL Server บางรุ่นการเพิ่มคอลัมน์ NOT NULL ด้วยค่าเริ่มต้นอาจใช้เวลานานในการดำเนินการให้เสร็จสมบูรณ์และสร้างบันทึกบันทึกจำนวนมาก คำสั่ง ALTER TABLE เหล่านี้ควรดำเนินการด้วยความระมัดระวังเช่นเดียวกับคำสั่ง INSERT, UPDATE หรือ DELETE ใด ๆ ที่มีผลต่อหลายแถว