IDENTITY_INSERT มีผลต่อการทำงานพร้อมกันอย่างไร


11

ฉันกำลังพยายามช่วยเหลือลูกค้าด้วยโปรแกรมเสริม SAP ของ บริษัท อื่นที่มีปัญหาการโพสต์และไม่ได้รับการสนับสนุน

ภายใต้สถานการณ์บางอย่างมันจะเก็บถาวรและโพสต์ที่ไม่สมบูรณ์จากตารางคิวการโพสต์ไปยังตารางเก็บถาวรการโพสต์ ฉันต้องการย้ายผลลัพธ์ที่เก็บถาวรเหล่านี้กลับไปที่คิว

ID ของคิวคือคอลัมน์ข้อมูลประจำตัวและฉันต้องการเก็บไว้เหมือนเดิม

คำถามคือถ้าฉันทำ identity_insert on / insert / identity_insert off ฉันจะคาดหวังอะไรเกี่ยวกับการเกิดพร้อมกันกับกระบวนการที่สร้างรายการคิวและคาดว่าคอลัมน์ identity จะถูกสร้างขึ้นโดยอัตโนมัติ?

พอยน์เตอร์ใด ๆ ในวิธีที่ดีที่สุดในการแสดงพฤติกรรมดังกล่าวจะได้รับการชื่นชมอย่างมากเช่นกัน

คำตอบ:


8

การตั้งค่า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 จะล้มเหลวด้วยการละเมิดคีย์หลัก นี่คือสวยเรียบง่ายการติดตั้งและทดสอบด้วยตัวเองกับบางWAITFORs:

-- 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เป็น) หากค่าดั้งเดิมมีความสำคัญมาก
  • เปลี่ยนกระบวนการเก็บถาวรเพื่อใช้ "การลบแบบอ่อน" ซึ่งบางสิ่งถูกทำเครื่องหมายว่าถูกเก็บถาวรในตอนแรกและการเก็บถาวรจะไม่ทำอย่างถาวรจนกว่าจะถึงวันที่ในภายหลัง จากนั้นกระบวนการใดก็ตามที่พยายามย้ายกลับไปสามารถทำได้เพียงอัปเดตโดยตรงและแก้ไขการตั้งค่าสถานะการลบแบบอ่อน

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