ล็อกการยกระดับ - เกิดอะไรขึ้นที่นี่


139

ในขณะที่แก้ไขตาราง (ลบคอลัมน์) ใน SQL Server 2008 ฉันคลิกปุ่มสร้างสคริปต์การเปลี่ยนแปลงและฉันสังเกตเห็นว่าสคริปต์การเปลี่ยนแปลงที่สร้างขึ้นจะลดลงในคอลัมน์กล่าวว่า "ไป" จากนั้นเรียกใช้คำสั่ง ALTER TABLE เพิ่มเติมที่ดูเหมือนจะตั้งค่า การเลื่อนระดับการล็อกสำหรับตารางเป็น "TABLE" ตัวอย่าง:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

ฉันควรสังเกตด้วยว่านี่เป็นสิ่งสุดท้ายที่สคริปต์การเปลี่ยนแปลงกำลังทำอยู่ มันทำอะไรที่นี่และทำไมจึงตั้งค่า LOCK_ESCALATION เป็น TABLE

คำตอบ:


169

" Lock Escalation " คือวิธีที่ SQL จัดการกับการล็อกสำหรับการอัปเดตขนาดใหญ่ เมื่อ SQL กำลังจะเปลี่ยนแถวจำนวนมากจะมีประสิทธิภาพมากขึ้นสำหรับเอ็นจินฐานข้อมูลที่จะใช้การล็อกน้อยลงและใหญ่ขึ้น (เช่นทั้งตาราง) แทนที่จะล็อกสิ่งเล็ก ๆ จำนวนมาก (เช่นล็อกแถว)

แต่สิ่งนี้อาจเป็นปัญหาได้เมื่อคุณมีโต๊ะขนาดใหญ่เนื่องจากการล็อกทั้งโต๊ะอาจล็อกการสืบค้นอื่น ๆ ไว้เป็นเวลานาน นั่นคือข้อเสีย: การล็อกแบบละเอียดขนาดเล็กจำนวนมากจะช้ากว่าการล็อกแบบหยาบน้อยกว่า (หรือหนึ่งรายการ) และการมีคำค้นหาหลายรายการที่ล็อกส่วนต่างๆของตารางจะทำให้เกิดการชะงักงันหากกระบวนการหนึ่งกำลังรออีกกระบวนการหนึ่ง

มีตัวเลือกระดับตารางซึ่งเป็นตัวเลือกLOCK_ESCALATIONใหม่ใน SQL 2008 ซึ่งช่วยให้สามารถควบคุมการเลื่อนระดับการล็อกได้ ค่าเริ่มต้น "TABLE" ช่วยให้การล็อกเลื่อนระดับไปจนถึงระดับตาราง DISABLE ป้องกันการเลื่อนระดับการล็อกไปยังตารางทั้งหมดในกรณีส่วนใหญ่ AUTO อนุญาตให้ล็อกตารางยกเว้นในกรณีที่ตารางถูกแบ่งพาร์ติชันซึ่งในกรณีนี้การล็อกจะสร้างขึ้นเฉพาะระดับพาร์ติชันเท่านั้น ดูโพสต์บล็อกนี้สำหรับข้อมูลเพิ่มเติม

ฉันสงสัยว่า IDE เพิ่มการตั้งค่านี้เมื่อสร้างตารางใหม่เนื่องจาก TABLE เป็นค่าเริ่มต้นใน SQL 2008 โปรดทราบว่า LOCK_ESCALATION ไม่ได้รับการสนับสนุนใน SQL 2005 ดังนั้นคุณจะต้องถอดออกหากพยายามเรียกใช้สคริปต์บน ตัวอย่างปี 2005 นอกจากนี้เนื่องจาก TABLE เป็นค่าเริ่มต้นคุณจึงสามารถลบบรรทัดนั้นได้อย่างปลอดภัยเมื่อเรียกใช้สคริปต์ของคุณอีกครั้ง

โปรดทราบว่าใน SQL 2005 ก่อนที่จะมีการตั้งค่านี้การล็อกทั้งหมดอาจเพิ่มขึ้นเป็นระดับตารางหรืออีกนัยหนึ่งคือ "TABLE" เป็นการตั้งค่าเดียวใน SQL 2005


1
โพสต์ซ้ำในฟอรัม MSDN เช่นกัน: social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/…
Jonathan Kehayias

6
@dma_k - ตัวเลือกนี้ไม่เกี่ยวข้องCREATE TABLEเนื่องจากตารางยังไม่มีอยู่จึงไม่มีอะไรให้ล็อก
Justin Grant

1
แต่ทำไมคำสั่ง LOCK_ESCALATION หลังคำสั่งALTER TABLE เริ่มต้นในสคริปต์การเปลี่ยนแปลงเมื่อออกแบบตารางใน SSMS แน่นอนเมื่อถึงเวลานั้นงานก็เสร็จเรียบร้อยแล้ว มันควรจะเป็นก่อนที่จะเปลี่ยนโครงสร้างของตารางไม่ใช่หรือ?
Reversed Engineer

2
@DaveBoltman - SET เป็นส่วนหนึ่งของคำสั่ง ALTER TABLE ไม่ใช่คำสั่งต่างหาก ดูdocs.microsoft.com/en-us/sql/t-sql/statements/…
Justin Grant

2
JustinGrant ยังคงเป็นคำถามจาก @DaveBoltman สคริปต์ที่ SSMS สร้างขึ้นกล่าวคือการเพิ่มคอลัมน์ใหม่มีสองALTER TABLEคำสั่งแยกกัน ครั้งแรกALTER TABLE ADD columnแล้วGOจากนั้นสองแล้วที่สองALTER TABLE SET LOCK_ESCALATION=TABLE GOดังนั้นจึงLOCK_ESCALATIONถูกตั้งค่าหลังจากเพิ่มคอลัมน์แล้ว อะไรคือจุดเริ่มต้นของความจริง? ALTER TABLEคำสั่งทั้งสองนี้รวมอยู่ในธุรกรรม แต่ยังคงมีการเพิ่มคอลัมน์ก่อนที่LOCK_ESCALATIONจะตั้งค่า ฉันคิดว่าฉันจะขุดลึกลงไปอีกเล็กน้อยและเขียนคำตอบอื่น
Vladimir Baranov

12

คุณสามารถตรวจสอบว่าคุณจำเป็นต้องรวมคำสั่ง LOCK_ESCALATION ในสคริปต์ของคุณหรือไม่โดยเปรียบเทียบค่านี้ก่อนและหลังการรันส่วนหลักของสคริปต์ของคุณ:

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

ในกรณีของฉันการแก้ไขตารางเพื่อวางหรือเพิ่มข้อ จำกัด ดูเหมือนจะไม่ได้แก้ไขค่านี้


12

คำตอบโดย 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_ESCALATIONUPDATE

ในที่สุดคำพูดจาก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 ใด ๆ ที่มีผลต่อหลายแถว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.