เราพบข้อผิดพลาดแปลก ๆ สามครั้งในช่วงสองสามวันที่ผ่านมาหลังจากปราศจากข้อผิดพลาดเป็นเวลา 8 สัปดาห์และฉันก็นิ่งงัน
นี่คือข้อความแสดงข้อผิดพลาด:
Executing the query "EXEC dbo.MergeTransactions" failed with the following error: "Cannot insert duplicate key row in object 'sales.Transactions' with unique index 'NCI_Transactions_ClientID_TransactionDate'. The duplicate key value is (1001, 2018-12-14 19:16:29.00, 304050920).".
ดัชนีที่เรามีไม่ซ้ำกัน หากคุณสังเกตเห็นค่าคีย์ที่ซ้ำกันในข้อความแสดงข้อผิดพลาดจะไม่ตรงกับดัชนี สิ่งที่แปลกคือถ้าฉันเรียกใช้ proc อีกครั้งมันก็ประสบความสำเร็จ
นี่คือลิงค์ล่าสุดที่ฉันพบว่ามีปัญหาของฉัน แต่ฉันไม่เห็นวิธีแก้ปัญหา
สองสามสิ่งเกี่ยวกับสถานการณ์ของฉัน:
- Proc กำลังอัปเดต TransactionID (ส่วนหนึ่งของคีย์หลัก) - ฉันคิดว่านี่เป็นสาเหตุของข้อผิดพลาด แต่ไม่รู้ว่าเพราะอะไร เราจะลบตรรกะนั้น
- เปิดใช้งานการติดตามการเปลี่ยนแปลงบนตาราง
- การทำธุรกรรมอ่านปราศจากข้อผูกมัด
มี 45 เขตข้อมูลสำหรับแต่ละตารางฉันส่วนใหญ่แสดงรายการที่ใช้ในดัชนี ฉันกำลังปรับปรุง TransactionID (คีย์คลัสเตอร์) ในคำสั่งการปรับปรุง (โดยไม่จำเป็น) แปลกที่เราไม่ได้มีปัญหาใด ๆ เป็นเวลาหลายเดือนจนถึงสัปดาห์ที่แล้ว และมันเกิดขึ้นเป็นระยะ ๆ ผ่าน SSIS เท่านั้น
โต๊ะ
USE [DB]
GO
/****** Object: Table [sales].[Transactions] Script Date: 5/29/2019 1:37:49 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[sales].[Transactions]') AND type in (N'U'))
BEGIN
CREATE TABLE [sales].[Transactions]
(
[TransactionID] [bigint] NOT NULL,
[ClientID] [int] NOT NULL,
[TransactionDate] [datetime2](2) NOT NULL,
/* snip*/
[BusinessUserID] [varchar](150) NOT NULL,
[BusinessTransactionID] [varchar](150) NOT NULL,
[InsertDate] [datetime2](2) NOT NULL,
[UpdateDate] [datetime2](2) NOT NULL,
CONSTRAINT [PK_Transactions_TransactionID] PRIMARY KEY CLUSTERED
(
[TransactionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=PAGE) ON [DB_Data]
) ON [DB_Data]
END
GO
USE [DB]
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[sales].[Transactions]') AND name = N'NCI_Transactions_ClientID_TransactionDate')
begin
CREATE NONCLUSTERED INDEX [NCI_Transactions_ClientID_TransactionDate] ON [sales].[Transactions]
(
[ClientID] ASC,
[TransactionDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = PAGE) ON [DB_Data]
END
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[sales].[DF_Transactions_Units]') AND type = 'D')
BEGIN
ALTER TABLE [sales].[Transactions] ADD CONSTRAINT [DF_Transactions_Units] DEFAULT ((0)) FOR [Units]
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[sales].[DF_Transactions_ISOCurrencyCode]') AND type = 'D')
BEGIN
ALTER TABLE [sales].[Transactions] ADD CONSTRAINT [DF_Transactions_ISOCurrencyCode] DEFAULT ('USD') FOR [ISOCurrencyCode]
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[sales].[DF_Transactions_InsertDate]') AND type = 'D')
BEGIN
ALTER TABLE [sales].[Transactions] ADD CONSTRAINT [DF_Transactions_InsertDate] DEFAULT (sysdatetime()) FOR [InsertDate]
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[sales].[DF_Transactions_UpdateDate]') AND type = 'D')
BEGIN
ALTER TABLE [sales].[Transactions] ADD CONSTRAINT [DF_Transactions_UpdateDate] DEFAULT (sysdatetime()) FOR [UpdateDate]
END
GO
ตารางชั่วคราว
same columns as the mgdata. including the relevant fields. Also has a non-unique clustered index
(
[BusinessTransactionID] [varchar](150) NULL,
[BusinessUserID] [varchar](150) NULL,
[PostalCode] [varchar](25) NULL,
[TransactionDate] [datetime2](2) NULL,
[Units] [int] NOT NULL,
[StartDate] [datetime2](2) NULL,
[EndDate] [datetime2](2) NULL,
[TransactionID] [bigint] NULL,
[ClientID] [int] NULL,
)
CREATE CLUSTERED INDEX ##workingTransactionsMG_idx ON #workingTransactions (TransactionID)
It is populated in batches (500k rows at a time), something like this
IF OBJECT_ID(N'tempdb.dbo.#workingTransactions') IS NOT NULL DROP TABLE #workingTransactions;
select fields
into #workingTransactions
from import.Transactions
where importrowid between two number ranges -- pseudocode
คีย์หลัก
CONSTRAINT [PK_Transactions_TransactionID] PRIMARY KEY CLUSTERED
(
[TransactionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION=PAGE) ON [Data]
) ON [Data]
ดัชนีที่ไม่ทำคลัสเตอร์
CREATE NONCLUSTERED INDEX [NCI_Transactions_ClientID_TransactionDate] ON [sales].[Transactions]
(
[ClientID] ASC,
[TransactionDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = PAGE)
คำสั่งการปรับปรุงตัวอย่าง
-- updates every field
update t
set
t.transactionid = s.transactionid,
t.[CityCode]=s.[CityCode],
t.TransactionDate=s.[TransactionDate],
t.[ClientID]=s.[ClientID],
t.[PackageMonths] = s.[PackageMonths],
t.UpdateDate = @UpdateDate
FROM #workingTransactions s
JOIN [DB].[sales].[Transactions] t
ON s.[TransactionID] = t.[TransactionID]
WHERE CAST(HASHBYTES('SHA2_256 ',CONCAT( S.[BusinessTransactionID],'|',S.[BusinessUserID],'|', etc)
<> CAST(HASHBYTES('SHA2_256 ',CONCAT( T.[BusinessTransactionID],'|',T.[BusinessUserID],'|', etc)
คำถามของฉันคือสิ่งที่เกิดขึ้นภายใต้ประทุน? และทางออกคืออะไร? สำหรับการอ้างอิงลิงก์ด้านบนกล่าวถึงสิ่งนี้:
ณ จุดนี้ฉันมีทฤษฎีไม่กี่:
- ข้อผิดพลาดที่เกี่ยวข้องกับแรงกดดันหน่วยความจำหรือแผนการอัปเดตขนานขนาดใหญ่ แต่ฉันคาดว่าจะมีข้อผิดพลาดประเภทอื่นและจนถึงตอนนี้ฉันไม่สามารถเชื่อมโยงทรัพยากรต่ำจะกำหนดกรอบเวลาของข้อผิดพลาดที่แยกและเป็นระยะ ๆ
- บั๊กในคำสั่ง UPDATE หรือข้อมูลทำให้เกิดการละเมิดที่ซ้ำกันจริงบนคีย์หลัก แต่ข้อผิดพลาด SQL Server ที่คลุมเครือบางอย่างเกิดขึ้นและข้อความแสดงข้อผิดพลาดที่อ้างอิงชื่อดัชนีผิด
- การอ่านสกปรกเกิดจากการแยกแบบไม่มีข้อผูกมัดทำให้เกิดการอัพเดตแบบขนานขนาดใหญ่เพื่อแทรกสองครั้ง แต่นักพัฒนา ETL อ้างว่าได้ใช้การอ่านเริ่มต้นแล้วและเป็นการยากที่จะกำหนดระดับการแยกที่กระบวนการใช้จริงในขณะรันไทม์
ฉันสงสัยว่าถ้าฉันปรับแต่งแผนการดำเนินการเป็นวิธีแก้ปัญหาบางที MAXDOP (1) คำใบ้หรือการใช้การตั้งค่าสถานะการติดตามเซสชันเพื่อปิดใช้งานการดำเนินการสปูลข้อผิดพลาดจะหายไป แต่ก็ไม่มีความชัดเจนว่าจะส่งผลกระทบอย่างไรต่อประสิทธิภาพ
รุ่น
Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64) 30 พ.ย. 2018 12:57:58 ลิขสิทธิ์ (C) 2017 Microsoft Corporation รุ่นองค์กร (64 บิต) บน Windows Server 2016 มาตรฐาน 10.0 (Build 14393) :)