ใน SQL Server ล็อคการอ่านทำงานอย่างไร


17

สมมติว่าฉันมีคิวรีที่ใช้เวลานานต่อไปนี้

UPDATE [Table1]
SET [Col1] = 'some value'
WHERE [Col2] -- some clause which selects thousands of rows

และสมมติว่ามีการดำเนินการค้นหาต่อไปนี้ขณะที่แบบสอบถามด้านบนทำงานอยู่

SELECT *
FROM [Table1]

แบบสอบถามแรกป้องกันไม่ให้แบบสอบถามที่สองทำงานจนกว่าแบบสอบถามแรกจะเสร็จสมบูรณ์หรือไม่ ถ้าใช่คิวรีแรกจะป้องกันไม่ให้คิวรีที่สองทำงานในแถวทั้งหมดหรือเฉพาะแถวที่เกี่ยวข้องในส่วนคำสั่ง WHERE หรือไม่

แก้ไข:

สมมติว่าแบบสอบถามที่สองคือ

SELECT [Col1], [Col2]
FROM [Table1]
WHERE [Col2] -- some clause whose matching elements overlap those from
             -- the clause in the first query and which has additional matching elements

คำตอบ:


14

ฉันขอแนะนำให้คุณอ่านทำความเข้าใจว่า SQL Server ดำเนินการสืบค้นอย่างไรมีคำอธิบายว่าอ่านและเขียนงานอย่างไรและวิธีการล็อคทำงานอย่างไร

มุมมอง 10000 ฟุตมีดังนี้:

  • ตัวดำเนินการอ่านจะได้รับการล็อคที่ใช้ร่วมกันกับข้อมูลที่พวกเขาอ่านก่อนที่จะอ่านข้อมูล
  • ตัวดำเนินการเขียนจะได้รับการล็อคแบบเอกสิทธิ์เฉพาะบุคคลบนข้อมูลที่พวกเขาแก้ไขก่อนที่จะแก้ไขข้อมูล
  • การล็อคข้อมูลเป็นเพียงสตริงเช่น แฮชของคีย์กำลังอ่านขอบเขตโดยฐานข้อมูลและวัตถุ
  • ตัวจัดการล็อกเก็บรักษารายการของการล็อกทั้งหมดที่ได้รับและตรวจสอบความเข้ากันไม่ได้ตามเมทริกซ์ล็อคความเข้ากันได้
  • คำขอที่เข้ากันไม่ได้จะถูกระงับจนกว่าการอนุญาตที่ไม่สามารถบล็อกได้จะถูกยกเลิก
  • ผู้ประกอบการใช้ลำดับชั้นล็อคเพื่อประกาศความตั้งใจที่จะอ่านหรือปรับปรุงข้อมูลในระดับที่สูงขึ้น (ระดับหน้าหรือตารางละเว้นตัวเลือกระดับพาร์ทิชัน) สิ่งนี้ทำให้ผู้ประกอบการสามารถล็อคตารางทั้งหมดโดยไม่มีการล็อคทุกแถว
  • อายุการใช้งานล็อคและช่วงล็อคใช้ในการบังคับใช้ระดับการแยกที่สูงขึ้น

นี่เป็นเพียงส่วนปลายของภูเขาน้ำแข็งเท่านั้น ตัวแบบนั้นกว้างใหญ่ ในตัวอย่างของคุณไม่มีใครสามารถตอบคำถามของคุณเกี่ยวกับสิ่งที่ถูกล็อคจริง ๆ เพราะมันจะขึ้นอยู่กับปัจจัยหลายอย่าง แน่นอนว่าแอปพลิเคชันไม่ควรออกSELECT * FROM Table1 เนื่องจากไม่มีส่วนคำสั่ง WHERE และใช้งาน*อยู่ สิ่งเหล่านี้เป็นแนวปฏิบัติที่ไม่ดีเพราะเหนือสิ่งอื่นใดพวกเขาจะนำไปสู่การโต้แย้งอย่างแน่นอน

หากคุณพบล็อคการอ่านและการเขียนคุณต้องดูการแยกเวอร์ชันและการแยกสแน็ปช็อต อ่านเข้าใจแถวรุ่นตามระดับการแยก


ถ้าฉันต้องการเนื้อหาทั้งหมดของตาราง (บอกว่าฉันมีเพียง 14 แถว) เป็นวิธีที่ไม่ดีหรือไม่SELECT * FROM Table1หากเป็นสิ่งที่ฉันต้องการ?
Azimuth

1
*ด้วยตัวมันเองคือการปฏิบัติที่ไม่ดีเพราะเมื่อโครงสร้างตารางการเปลี่ยนแปลงแอปพลิเคชันมักจะแบ่ง (คอลัมน์ที่ไม่คาดคิดปรากฏในผล)
Remus Rusanu

3

แก้ไข: เนื่องจาก@MaxVernonชี้ให้เห็นต่อไปนี้ไม่แนะนำให้ใช้ NOLOCKและฉันควรกล่าวถึงการตั้งค่าระดับการทำธุรกรรมเป็นอย่างดีREAD UNCOMMITEDและให้ความหมายเชิงลบมีอยู่มากกว่าที่จะNOLOCKปรากฏขึ้นในตอนแรก ดังนั้นตามที่โพสต์เดิม:

วิธีที่ง่ายและรวดเร็วคือ "ใช่แบบสอบถามแรกจะบล็อกข้อความค้นหาที่สองยกเว้นว่ามีการระบุคำใบ้ดัชนีเฉพาะ ( NOLOCKบางครั้งเรียกว่า" อ่านสกปรก ") หรือตั้งระดับการแยกธุรกรรมของแบบสอบถามที่สองเป็นREAD UNCOMMITED(ซึ่งทำงานเหมือนกัน) ไม่มันไม่ได้ "

ในการตอบสนองต่อรายละเอียดเพิ่มเติมที่ให้ไว้ในคำถามที่เกี่ยวข้องกับการรวมของWITHประโยคที่สองSELECTเป็นพิเศษร่วมกันหรืออย่างอื่นปฏิสัมพันธ์ระหว่างทั้งสองแบบสอบถามจะส่วนใหญ่เหมือนกัน

IF NOT EXISTS ( SELECT  1
                FROM    sys.objects
                WHERE   name = 'Foo'
                    AND type = 'U' )
BEGIN
    --DROP TABLE dbo.Foo;
    CREATE TABLE dbo.Foo
    (
        Foo_PK          BIGINT IDENTITY( 1, 1 ) NOT NULL,
                            PRIMARY KEY ( Foo_PK ),
        Bar             BIT,
        x               BIT,
        y               BIT,
        z               BIT
    );

    CREATE NONCLUSTERED INDEX IX_Foo_x
        ON  dbo.Foo ( x );

    INSERT INTO dbo.Foo ( Bar, x, y, z )
    VALUES ( 1, 1, 1, 1 ), ( 0, 0, 0, 0 );
END;    
GO

BEGIN TRANSACTION;

UPDATE  dbo.Foo
    SET y = 0
WHERE   x = 1;

-- COMMIT TRANSACTION;

ในเซสชั่นแยกต่างหากเรียกใช้ต่อไปนี้:

SELECT  *
FROM    dbo.Foo WITH ( NOLOCK );
GO

SELECT  *
FROM    dbo.Foo;

คุณสามารถตรวจสอบล็อคปัจจุบันที่มีอยู่โดยการทำงานsp_lockโดยเฉพาะอย่างยิ่งในเซสชั่นที่แยกต่างหากอื่น:

EXECUTE dbo.sp_lock;

คุณควรเห็นKEYประเภทการล็อกที่ถูกเก็บไว้โดย spid ที่ทำธุรกรรมการแทรกในXโหมด (พิเศษ) เพื่อไม่ให้สับสนกับการIXล็อคอื่น ๆ(Intent-Exclusive) ล็อคเอกสารแสดงให้เห็นว่าในขณะที่KEYล็อคเป็นช่วงที่เฉพาะเจาะจงก็ยังช่วยป้องกันการทำธุรกรรมอื่น ๆ จากการแทรกหรือปรับปรุงคอลัมน์ได้รับผลกระทบโดยการเปลี่ยนแปลงข้อมูลที่อยู่ในนั้นเพื่อที่จะสามารถอยู่ในช่วงของการค้นหาเดิมที่ เนื่องจากล็อคตัวเองถูกเก็บไว้เป็นพิเศษแบบสอบถามแรกคือการป้องกันการเข้าถึงทรัพยากรจากการทำธุรกรรมที่เกิดขึ้นพร้อมกันอื่น ๆ ผลแถวทั้งหมดของคอลัมน์จะถูกล็อคไม่ว่าจะอยู่ในช่วงที่ระบุโดยแบบสอบถามแรกหรือไม่ก็ตาม

Sล็อคถูกจัดขึ้นโดยช่วงที่สองจึงจะWAITจนXล้างล็อคป้องกันไม่ให้อีกX(หรือU) ล็อคจากการถูกนำทรัพยากรนั้นจาก spid พร้อมกันแตกต่างกันก่อนช่วงที่สองเสร็จสิ้นการดำเนินการอ่านของตนสมควรดำรงอยู่ของSล็อค

ตอนนี้การแก้ไขเพื่อความชัดเจน: นอกจากว่าฉันเข้าใจผิดในสิ่งที่สกปรกอ่านมาจากคำอธิบายสั้น ๆ ของความเสี่ยงที่กล่าวถึงที่นี่ ... แก้ไข 3 : ฉันเพิ่งรู้ว่าฉันไม่ได้พิจารณาผลกระทบของจุดตรวจพื้นหลังที่เขียนเป็น จากธุรกรรมที่ยังไม่ได้รับการยอมรับไปยังดิสก์ดังนั้นใช่คำอธิบายของฉันทำให้เข้าใจผิด

ในแบบสอบถามที่สองชุดแรกสามารถ (และในกรณีนี้จะ) ส่งคืนข้อมูลที่ไม่มีข้อผูกมัด ชุดที่สองที่ทำงานในระดับการแยกธุรกรรมเริ่มต้นREAD COMMITEDจะกลับมาหลังจากเสร็จสิ้นการยอมรับหรือย้อนกลับในเซสชั่นแรก

จากที่นี่คุณสามารถดูแผนแบบสอบถามของคุณและระดับล็อคที่เกี่ยวข้อง แต่ยังดีกว่าคุณสามารถอ่านทั้งหมดเกี่ยวกับการล็อคใน SQL Server ที่นี่


1
คำเตือนเกี่ยวกับการใช้WITH (NOLOCK)จะเป็นประโยชน์ในกรณีนี้ ดูbrentozar.com/archive/2011/11/…และbrentozar.com/archive/2013/02/…สำหรับการอ่านเพิ่มเติม
Max Vernon

3
โอ้WITH (NOLOCK)คำใบ้ไม่ได้ส่งคืนหน้าสกปรกจากหน่วยความจำที่ยังไม่ได้รับการยืนยัน จริงๆแล้วมันจะอ่านแถวจากตาราง (ไม่ว่าจะเป็นบนดิสก์หรือในหน่วยความจำแคช) โดยไม่ปิดกั้นผู้เขียนจากการปรับปรุงหรือเพิ่มแถวไปยังหน้าที่ใช้โดยตาราง
Max Vernon

2
ฉันสับสน หากคำตอบของ "แบบสอบถามที่ 1 ป้องกันไม่ให้ 2nd ทำงานหรือไม่" คือ "ไม่" คำตอบของคำถามที่สองจะเป็น "ใช่" ได้อย่างไร คุณช่วยชี้แจงคำถามที่คุณตอบและขยายคำตอบของคุณได้หรือไม่?
Jon of All Trades

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