จะไม่มีปัญหาหากตัวแปร table มีค่าเพียงค่าเดียวเท่านั้น มีหลายแถวมีความเป็นไปได้ใหม่สำหรับการหยุดชะงัก สมมติว่ากระบวนการที่เกิดขึ้นพร้อมกันสองตัว (A & B) ทำงานกับตัวแปรตารางที่มี (1, 2) และ (2, 1) สำหรับ บริษัท เดียวกัน
กระบวนการ A อ่านปลายทางไม่พบแถวและใส่ค่า '1' มันถือล็อคแถวพิเศษกับค่า '1' กระบวนการ B อ่านปลายทางไม่พบแถวและใส่ค่า '2' มันถือล็อคแถวพิเศษกับค่า '2'
ตอนนี้โปรเซส A ต้องการประมวลผลแถวที่ 2 และโปรเซส B จำเป็นต้องดำเนินการกับแถวที่ 1 กระบวนการทั้งสองไม่สามารถดำเนินการได้เนื่องจากต้องใช้การล็อกที่เข้ากันไม่ได้กับการล็อคแบบเอกสิทธิ์เฉพาะบุคคลที่ถือโดยกระบวนการอื่น
เพื่อหลีกเลี่ยงการติดตายกับแถวหลายแถวที่จะต้องมีการประมวลผล (และตารางการเข้าถึง) ในลำดับเดียวกันทุกครั้ง ตัวแปรตารางในแผนการดำเนินการที่แสดงในคำถามคือฮีปดังนั้นแถวไม่มีลำดับที่แท้จริง (มีแนวโน้มที่จะอ่านตามลำดับการแทรกแม้ว่าจะไม่รับประกัน)
การขาดลำดับการประมวลผลแถวที่สอดคล้องจะนำไปสู่โอกาสการหยุดชะงักโดยตรง ข้อพิจารณาที่สองคือการขาดการรับประกันความเป็นเอกลักษณ์ที่สำคัญหมายความว่า Table Spool จำเป็นต่อการป้องกันฮาโลวีนที่ถูกต้อง สปูลเป็นสปูลกระตือรือร้นซึ่งหมายความว่าทุกแถวจะถูกเขียนไปยังโต๊ะทำงานtempdbก่อนที่จะอ่านและเล่นซ้ำสำหรับตัวดำเนินการแทรก
นิยามใหม่TYPE
ของตัวแปร table เพื่อรวมคลัสเตอร์PRIMARY KEY
:
DROP TYPE dbo.CoUserData;
CREATE TYPE dbo.CoUserData
AS TABLE
(
MyKey integer NOT NULL PRIMARY KEY CLUSTERED,
MyValue integer NOT NULL
);
แผนการดำเนินการในขณะนี้แสดงการสแกนของดัชนีคลัสเตอร์และการรับประกันความเป็นเอกลักษณ์หมายความว่าเครื่องมือเพิ่มประสิทธิภาพสามารถลบ Table Spool ได้อย่างปลอดภัย:
ในการทดสอบด้วยMERGE
คำสั่ง5,000 ซ้ำของคำสั่งบน 128 เธรดจะไม่มีการหยุดชะงักเกิดขึ้นกับตัวแปรตารางคลัสเตอร์ ฉันควรจะเน้นว่านี่เป็นเพียงการสังเกตเท่านั้น ตัวแปรตารางคลัสเตอร์ยังสามารถสร้างเทคนิคในแถวของคำสั่งที่หลากหลาย แต่โอกาสของคำสั่งที่สอดคล้องกันนั้นได้รับการปรับปรุงอย่างมาก ลักษณะการทำงานที่สังเกตจะต้องมีการ retested สำหรับการปรับปรุงสะสมเซอร์วิสแพ็คหรือ SQL Server รุ่นใหม่ทุกครั้ง
ในกรณีที่นิยามตัวแปรตารางไม่สามารถเปลี่ยนแปลงได้มีทางเลือกอื่น:
MERGE dbo.CompanyUser AS R
USING
(SELECT DISTINCT MyKey, MyValue FROM @DataTable) AS NewData ON
R.CompanyId = @CompanyID
AND R.UserID = @UserID
AND R.MyKey = NewData.MyKey
WHEN NOT MATCHED THEN
INSERT
(CompanyID, UserID, MyKey, MyValue)
VALUES
(@CompanyID, @UserID, NewData.MyKey, NewData.MyValue)
OPTION (ORDER GROUP);
นอกจากนี้ยังสามารถกำจัดสปูล (และความสอดคล้องของคำสั่งแถว) ได้ด้วยค่าใช้จ่ายในการแนะนำการจัดเรียงที่ชัดเจน:
แผนนี้ไม่มีการหยุดชะงักโดยใช้การทดสอบเดียวกัน สคริปต์การสืบพันธุ์ด้านล่าง:
CREATE TYPE dbo.CoUserData
AS TABLE
(
MyKey integer NOT NULL /* PRIMARY KEY */,
MyValue integer NOT NULL
);
GO
CREATE TABLE dbo.Company
(
CompanyID integer NOT NULL
CONSTRAINT PK_Company
PRIMARY KEY (CompanyID)
);
GO
CREATE TABLE dbo.CompanyUser
(
CompanyID integer NOT NULL,
UserID integer NOT NULL,
MyKey integer NOT NULL,
MyValue integer NOT NULL
CONSTRAINT PK_CompanyUser
PRIMARY KEY CLUSTERED
(CompanyID, UserID, MyKey),
FOREIGN KEY (CompanyID)
REFERENCES dbo.Company (CompanyID),
);
GO
CREATE NONCLUSTERED INDEX nc1
ON dbo.CompanyUser (CompanyID, UserID);
GO
INSERT dbo.Company (CompanyID) VALUES (1);
GO
DECLARE
@DataTable AS dbo.CoUserData,
@CompanyID integer = 1,
@UserID integer = 1;
INSERT @DataTable
SELECT TOP (10)
V.MyKey,
V.MyValue
FROM
(
VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9)
) AS V (MyKey, MyValue)
ORDER BY NEWID();
BEGIN TRANSACTION;
-- Test MERGE statement here
ROLLBACK TRANSACTION;