【发布时间】:2015-09-07 13:28:56
【问题描述】:
在 M$ SQL server 2014 (v.12.0.4100.1) 中: 我正在尝试使用@@rowcount 将一个表(~3'500'000'000 行)批量复制到另一个表。 两个表在 ([timestamp],[NumericID]) 上都有唯一索引。
问题是,在一些成功的循环之后,我遇到了主键违规,例如:
ErrorNumber ErrorSeverity ErrorState ErrorLine ErrorProcedure ErrorMessage: 2627 14 1 52 NULL 违反主键约束“PK_DataHist_2”。 无法在对象“dbo.DataHist_2”中插入重复键。复制品 键值为(2014 年 7 月 14 日下午 4:27,5011)。
键值总是不同的。错误发生在不同数量的循环后,似乎是随机的。
似乎 SQL 语句 SOMETIMES 返回 @@rowcount = 0。
我不知道为什么会这样。有人可以指出我做错了什么吗?
-- copy data from DataHist to DataHist_2
/* SRC table def:
CREATE TABLE [dbo].[DataHist](
[ID] [BIGINT] IDENTITY(1,1) NOT NULL,
[TimeStamp] [DATETIME] NOT NULL,
[NumericID] [INT] NOT NULL,
[BadQ] [BIT] NULL CONSTRAINT [DF_DataHist_BadQ] DEFAULT (NULL),
[Quality] AS (CASE ISNULL([BadQ],(0)) WHEN (0) THEN (1) ELSE (0) END),
[Value] [VARCHAR](8000)
CONSTRAINT [PK_DataHist] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
)
CREATE UNIQUE NONCLUSTERED INDEX [IX_DataHist_Time_NumID] ON [dbo].[DataHist]
(
[NumericID] ASC,
[TimeStamp] ASC
)
*/
/* Dest table:
CREATE TABLE [dbo].[DataHist_2](
[TimeStamp] [datetime] NOT NULL,
[NumericID] [int] NOT NULL,
[Value] [varchar](8000) NULL,
[BadQ] [bit] NULL CONSTRAINT [DF_DataHist_2_BadQ] DEFAULT (NULL),
[Quality] AS (case isnull([BadQ],(0)) when (0) then (1) else (0) end),
CONSTRAINT [PK_DataHist_2] PRIMARY KEY CLUSTERED
(
[TimeStamp] ASC,
[NumericID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) -- ON [DataHistFG]
) -- ON [DataHistFG]
*/
BEGIN TRY
SET XACT_ABORT ON;
SET NOCOUNT ON;
PRINT 'copy data from DataHist to DataHist_2';
PRINT GETUTCDATE();
DECLARE @nextID BIGINT = 1;
DECLARE @r INT ,
@N INT = 1000000;
DECLARE @s VARCHAR(1000);
DECLARE @t0 DATETIME;
SET @r = 1;
-- find where to re-start copying:
SET @nextID = ( SELECT TOP ( 1 )
ID
FROM dbo.DataHist DH
WHERE NOT EXISTS ( SELECT 1
FROM dbo.DataHist_2 DH2
WHERE DH.TimeStamp = DH2.TimeStamp
AND DH.NumericID = DH2.NumericID )
ORDER BY DH.ID
);
PRINT @nextID;
PRINT GETUTCDATE();
-- insert in batches of @N:
WHILE @r > 0
BEGIN
BEGIN TRANSACTION;
SET @t0 = GETUTCDATE();
INSERT INTO dbo.DataHist_2
( TimeStamp ,
NumericID ,
BadQ ,
Value
)
SELECT TOP ( @N )
TimeStamp ,
NumericID ,
BadQ ,
Value
FROM dbo.DataHist
WHERE ID >= @nextID
ORDER BY ID
SET @r = @@ROWCOUNT;
SET @nextID = @nextID + @r;
SET @s = 'nextID=' + CAST(@nextID AS VARCHAR(30)) + ', t='
+ CAST(DATEDIFF(SECOND, @t0, GETUTCDATE()) AS VARCHAR(1000));
PRINT @s;
COMMIT TRANSACTION;
END;
PRINT GETUTCDATE();
PRINT 'END';
END TRY
BEGIN CATCH
PRINT 'Catch Exception'
IF @@trancount > 0
BEGIN
PRINT 'Rolling back transaction.';
ROLLBACK TRANSACTION;
END;
EXEC usp_GetErrorInfo;
END CATCH;
【问题讨论】:
-
为什么要重新设置
id?只需使用identity列。 -
你的问题是为什么@@rowcount 由于主键违规而插入不成功时为0?
-
您是否检查了源表中有多少 id 为 5011 的行?
-
你检查你的来源是否有重复?
标签: sql-server