지난 며칠 동안 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) 힌트 또는 세션 추적 플래그를 사용하여 스풀 작업을 사용하지 않도록 설정하면 오류가 사라지지만 이것이 성능에 어떤 영향을 미치는지 확실하지 않습니다.
버전
Windows Server 2016 Standard 10.0의 Microsoft SQL Server 2017 (RTM-CU13) (KB4466404)-14.0.3048.4 (X64) 11 월 30 2018 12:57:58 Copyright (C) 2017 Microsoft Corporation Enterprise Edition (64 비트) (빌드 14393 :)