การตั้งค่าIDENTITY_INSERT ON
ด้วยตัวเองไม่ได้กำจัดการทำงานพร้อมกัน - สิ่งนี้ไม่ได้วางการล็อกแบบเอกสิทธิ์เฉพาะบุคคลบนตารางเพียงการล็อค schema S (S-) แบบย่อ
ดังนั้นในทางทฤษฎีสิ่งที่อาจเกิดขึ้นภายใต้พฤติกรรมเริ่มต้นคือคุณสามารถทำได้ในเซสชั่น 1:
BEGIN TRANSACTION;
-- 1
SET IDENTITY_INSERT dbo.tablename ON;
-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101
-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102
-- 4
SET IDENTITY_INSERT dbo.tablename OFF;
COMMIT TRANSACTION;
ในเซสชั่นอื่นคุณสามารถแทรกแถวลงในตารางที่จุด 1, 2, 3 หรือ 4 ซึ่งอาจดูเหมือนเป็นสิ่งที่ดียกเว้นสิ่งที่เกิดขึ้นสำหรับการแทรกใด ๆ ที่เกิดขึ้นระหว่าง 2 และ 3 คือค่าที่สร้างขึ้นโดยอัตโนมัติ โดยเซสชั่นอื่นจะขึ้นอยู่กับผลของคำสั่งที่ 2 - ดังนั้นมันจะสร้าง 101 และจากนั้นคำสั่งที่ 3 จะล้มเหลวด้วยการละเมิดคีย์หลัก นี่คือสวยเรียบง่ายการติดตั้งและทดสอบด้วยตัวเองกับบางWAITFOR
s:
-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;
SET IDENTITY_INSERT dbo.what ON;
INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);
SET IDENTITY_INSERT dbo.what OFF;
COMMIT TRANSACTION;
เมื่อแบตช์นั้นได้เริ่มขึ้นให้เริ่มแบทช์นี้ในหน้าต่างอื่น:
-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20
ช่วงที่ 2 ควรแทรกค่าตั้งแต่ 1-20 เท่านั้นใช่ไหม ยกเว้นว่าเป็นเพราะข้อมูลประจำตัวพื้นฐานได้รับการปรับปรุงโดยแทรกคู่มือของคุณเซสชั่น 1 ในบางจุดเซสชั่น 2 จะรับที่ที่เซสชั่น 1 ซ้ายและแทรก 32 หรือ 33 หรือ 34 หรือ 34 ฯลฯ มันจะได้รับอนุญาตให้ทำ จากนั้นเซสชัน 1 จะล้มเหลวในส่วนแทรกครั้งถัดไปที่มีการละเมิด PK (ผู้ชนะคนใดอาจเป็นเรื่องของเวลา)
วิธีหนึ่งในการแก้ไขปัญหานี้คือการเรียกใช้TABLOCK
การแทรกครั้งแรก
INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);
การดำเนินการนี้จะบล็อกผู้ใช้รายอื่นที่พยายามแทรก (หรือทำสิ่งใด ๆ ด้วยตนเอง) ด้วยตารางนี้จนกว่าคุณจะย้ายแถวที่เก็บถาวรเหล่านั้นกลับไป การทำงานพร้อมกันของ throttles นี้แน่นอน แต่นี่เป็นวิธีที่คุณต้องการปิดกั้นการทำงาน และหวังว่านี่จะไม่ใช่สิ่งที่เกิดขึ้นในอัตราที่คุณต้องบล็อกคนอื่นตลอดเวลา
วิธีแก้ปัญหาอื่นสองสามข้อ:
- หยุดใส่ใจเกี่ยวกับ
IDENTITY
ค่าที่สร้างขึ้น ใครสน? ใช้ a UNIQUEIDENTIFIER
(อาจสร้างในตารางแยกโดยมีเครื่องหมายIDENTITY
เป็น) หากค่าดั้งเดิมมีความสำคัญมาก
- เปลี่ยนกระบวนการเก็บถาวรเพื่อใช้ "การลบแบบอ่อน" ซึ่งบางสิ่งถูกทำเครื่องหมายว่าถูกเก็บถาวรในตอนแรกและการเก็บถาวรจะไม่ทำอย่างถาวรจนกว่าจะถึงวันที่ในภายหลัง จากนั้นกระบวนการใดก็ตามที่พยายามย้ายกลับไปสามารถทำได้เพียงอัปเดตโดยตรงและแก้ไขการตั้งค่าสถานะการลบแบบอ่อน