ALLOW_SNAPSHOT_ISOLATION และ READ_COMMITTED_SNAPSHOT


38

ฟอรัมและตัวอย่างแบบออนไลน์ส่วนใหญ่มักแนะนำให้มีทั้งสองอย่างALLOW_SNAPSHOT_ISOLATIONและREAD_COMMITTED_SNAPSHOTตั้งค่าเป็นเปิดเมื่อใดก็ตามที่มีคนถามสแนปชอตการกำหนดเวอร์ชันของแถวหรือคำถามที่คล้ายกัน

ฉันเดาคำว่า SNAPSHOT ในการตั้งค่าทั้งสองทำให้สับสนเล็กน้อย ผมคิดว่าในการสั่งซื้อสำหรับโปรแกรมฐานข้อมูลที่จะใช้เวอร์ชันแถวแทนการล็อคสำหรับการทำงานเริ่มต้น READ_COMMITTED ฐานข้อมูลREAD_COMMITTED_SNAPSHOTเป็นชุดที่ ON โดยไม่คำนึงถึงสิ่งที่ALLOW_SNAPSHOT_ISOLATIONการตั้งค่า

ALLOW_SNAPSHOT_ISOLATIONตั้งค่าจะถูกตั้งไว้ที่ ON เท่านั้นที่จะช่วยให้ภาพรวมการแยกเมื่อเริ่มต้นการทำธุรกรรม (เช่น SET แยกธุรกรรมระดับภาพรวม) โดยไม่คำนึงถึงของREAD_COMMITTED_SNAPSHOTการตั้งค่า

เหตุผลเดียวที่มีการตั้งค่าทั้งสองนี้เป็น ON คือเมื่อต้องมีการอ่านการกำหนดเวอร์ชันแถวที่ยอมรับและ การแยกสแน็ปช็อต

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

คำตอบ:


25

ความเข้าใจของคุณถูกต้อง มันทำให้สับสนเล็กน้อย

คิม Tripp (หนึ่งในการเขียนโปรแกรมของ SQL Server และเป็นส่วนหนึ่งของ SQLSkills) ที่ผ่านไปว่าสิ่งที่คุณระบุไว้ในวิดีโอ MCM ในภาพรวมการแยก กด fwd ที่ 41:45 ในวิดีโอเพื่อไปยังส่วนที่เธอตอบคำถามของคุณ

หากคุณใช้ALLOW_SNAPSHOT_ISOLATIONให้แน่ใจว่าคุณใช้SET TRANSACTION ISOLATION LEVEL SNAPSHOTในรหัสของคุณมิฉะนั้นคุณจะไม่ได้รับผลประโยชน์ใด ๆ

หากคุณตั้งค่าคุณSET READ_COMMITTED_SNAPSHOT ONไม่จำเป็นต้องแก้ไขรหัสใด ๆ MS SQL Server ใช้การแยกสแน็ปช็อตโดยอัตโนมัติสำหรับตารางนั้น

ฉันยังไม่ได้ทดสอบเพื่อดูว่าจะเกิดอะไรขึ้นถ้าคุณขอระดับการแยกอื่นในรหัสของคุณฉันสงสัยว่ามันจะเขียนทับตัวเลือกนี้ แต่ทดสอบก่อน

ดูอย่างรวดเร็วเกี่ยวกับค่าใช้จ่ายด้านประสิทธิภาพโดยใช้ Snapshot Isolation

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


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

4
นี่เป็นคำตอบที่ดีมากและฉันต้องการจะอธิบายบางรายการเท่านั้น ก่อนอื่นถ้าคุณเพิ่งสแกนวิดีโอให้เริ่มที่ 23:18 และ 41:45 เวลาก่อนเพิ่มรายละเอียดเพิ่มเติม แม้ว่าคิมจะกล่าวคำตอบสำหรับคำถามต้นฉบับ แต่ก็ยังมีความจำเป็นที่จะต้องแก้ไขรหัสหากใช้ทั้งคู่ Read_Committed_Snapshot เป็นการแยกระดับคำสั่งในคำอื่น ๆ ที่ใช้กับคำสั่งที่กำลังทำงานอยู่เท่านั้น Allow_Snapshot_Isolation เป็นการแยกระดับธุรกรรมทุกอย่างระหว่าง Begin Tran และ Commit พวกเขาสามารถมีส่วนร่วมแยกต่างหาก แต่ค่าใช้จ่าย 14 ไบต์ต่อแถวเดียวกันจะถูกสร้างขึ้น
Delux

ขอบคุณสำหรับการเพิ่มรายละเอียดเพิ่มเติมเกี่ยวกับค่าใช้จ่าย 14 ไบต์ที่ถูกสร้างขึ้น คิมผ่านมันไปในวิดีโอ แต่มันมีประโยชน์มากที่จะมีไว้ที่นี่ในข้อความเช่นกัน
Ali Razeghi

15

ตกลงกลับบ้านแล้วทดสอบ นี่คือการสังเกต

CREATE DATABASE TEST;
GO
CREATE TABLE TABLE1
(
    ID tinyint,
    Details varchar(10)
);
GO
INSERT INTO TABLE1
VALUES (1, 'Original');
GO

SELECT
    name,
    snapshot_isolation_state_desc,
    is_read_committed_snapshot_on
FROM sys.databases
WHERE name = 'TEST';
GO

การทดสอบครั้งแรกกับการตั้งค่าทั้งสองยืนยันว่าปิด

แบบสอบถาม 1

USE TEST;

BEGIN TRAN
UPDATE TABLE1
SET Details = 'Update'
WHERE ID = 1;

--COMMIT;
--ROLLBACK;
GO

แบบสอบถาม 2

USE TEST;

SELECT ID, Details
FROM TABLE1
WHERE ID = 1;
GO

ในการทดสอบนี้แบบสอบถาม 2 กำลังรอให้แบบสอบถาม 1 ส่งมอบ, dm_tran_locks DMV แสดงให้เห็นว่าล็อคแบบเอกสิทธิ์เฉพาะบุคคลใน Table1 ที่เกิดขึ้นจากแบบสอบถาม 1

USE TEST;

SELECT
    DB_NAME(tl.resource_database_id) AS DBName,
    resource_type,
    OBJECT_NAME(resource_associated_entity_id) AS tbl_name,
    request_mode,
    request_status,
    request_session_id
FROM sys.dm_tran_locks tl
WHERE 
    resource_database_id = db_id('TEST')
    AND resource_type = 'OBJECT'

การทดสอบครั้งที่สองย้อนกลับธุรกรรมก่อนหน้าตั้งค่า READ_COMMITTED_SNAPSHOT แต่ให้ปิด ALLOW_SNAPSHOT_ISOLATION

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT ON
WITH ROLLBACK IMMEDIATE;
GO

เรียกใช้ Query 1 และเรียกใช้แบบสอบถาม 2 DMV แสดงแบบสอบถาม 1 มีการล็อกแบบเอกสิทธิ์เฉพาะบุคคล แต่แบบสอบถาม 2 ส่งกลับรายละเอียดด้วย 'ดั้งเดิม' โดยไม่มีแบบสอบถาม 1 ยอมรับธุรกรรม ปรากฏว่ามีการกำหนดเวอร์ชันแถว READ_COMMITTED

การเพิ่มSET TRANSACTION ISOLATION LEVEL SNAPSHOT;ในแบบสอบถาม 1 และแบบสอบถาม 2 และเรียกใช้แบบสอบถาม 1 หรือแบบสอบถาม 2 ส่งคืนข้อผิดพลาด - ธุรกรรมแยก Snapshot ล้มเหลวในการเข้าถึงฐานข้อมูล 'ทดสอบ' เนื่องจากไม่อนุญาตให้มีการแยกสแนปชอตในฐานข้อมูลนี้ ใช้ ALTER DATABASE เพื่ออนุญาตการแยกสแน็ปช็อต

การทดสอบที่สามย้อนกลับการทำธุรกรรมก่อนหน้า ตั้งค่า READ_COMMITTED_SNAPSHOT OFF และเปิด ALLOW_SNAPSHOT_ISOLATION

ALTER DATABASE TEST
SET READ_COMMITTED_SNAPSHOT OFF
WITH ROLLBACK IMMEDIATE;
GO

ALTER DATABASE TEST
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

เรียกใช้แบบสอบถาม 1 และแบบสอบถาม 2 DMV แสดงการล็อกแบบเอกสิทธิ์เฉพาะบุคคลที่เกิดขึ้นจากแบบสอบถาม 1 แบบสอบถาม 2 ดูเหมือนจะรอให้แบบสอบถาม 1 ให้เสร็จสมบูรณ์ การเปิด ALLOW_SNAPSHOT_ISOLATION ON ไม่ปรากฏขึ้นเพื่อเปิดใช้งานการกำหนดเวอร์ชัน READ COMMITTED แถว

การเพิ่มSET TRANSACTION ISOLATION LEVEL SNAPSHOT;ทั้งคิวรี 1 และคิวรี 2 เรียกใช้คิวรี 1 และคิวรี 2 ในขณะที่ DMV แสดงคิวรี 1 ที่มีการล็อกแบบเอกสิทธิ์เฉพาะบุคคลนั้นคิวรี 2 จะส่งกลับรายละเอียดด้วย 'ดั้งเดิม' ดูเหมือนจะมีการแยกสแนปชอต

การสังเกตจากการทดสอบแสดงให้เห็นว่าREAD_COMMITTED_SNAPSHOTตัวเองเปิดใช้งาน / ปิดใช้งานการกำหนดเวอร์ชัน READ COMMITTED แถวโดยไม่คำนึงถึงALLOW_SNAPSHOT_ISOLATIONการตั้งค่าและในทางกลับกัน


4

ความเข้าใจของคุณถูกต้อง ฉันชอบคำจำกัดความสั้น ๆ สะอาดและเรียบง่ายจากที่นี่ :

เมื่อตัวเลือกฐานข้อมูล READ_COMMITTED_SNAPSHOT เปิดอยู่ธุรกรรมที่ตั้งค่าระดับการแยกที่อ่านได้แล้วจะใช้การกำหนดเวอร์ชันของแถว

เมื่อตัวเลือกฐานข้อมูล ALLOW_SNAPSHOT_ISOLATION เปิดอยู่การทำธุรกรรมสามารถตั้งค่าระดับการแยกสแน็ปช็อต

ดูเหมือนว่าความเข้าใจผิดมากมายมาจาก MS เอง ตัวอย่างเช่นที่นี่พวกเขาพูดว่า:

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

แต่ "แยกภาพรวม" ที่กล่าวถึงไม่เท่ากับพฤติกรรมของการทำธุรกรรมที่set transaction isolation level snapshotใช้

สำหรับความแตกต่างคำอธิบายที่ดีคือที่นี่

อาจเป็นเรื่องที่ดีกว่าถ้า READ_COMMITTED_SNAPSHOT ถูกตั้งชื่อเป็น READ_COMMITTED_ROW_VERSIONING หรืออะไรทำนองนั้น :)


0

ฉันชอบข้อมูลสรุปจาก Microsoft :

การตั้งค่าตัวเลือก READ_COMMITTED_SNAPSHOT ON อนุญาตให้เข้าถึงแถวที่มีเวอร์ชันภายใต้ระดับการแยก READ COMMITTED เริ่มต้น ถ้าตัวเลือก READ_COMMITTED_SNAPSHOT ถูกตั้งค่าเป็นปิดคุณต้องตั้งค่าระดับการแยก Snapshot สำหรับแต่ละเซสชันอย่างชัดเจนเพื่อเข้าถึงแถวที่มีเวอร์ชัน

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