【问题标题】:Getting SOMETIMES wrong @@rowcount after INSERT (..) SELECT.. (SQL-server 2014)在 INSERT (..) SELECT.. (SQL-server 2014) 之后得到错误的 @@rowcount
【发布时间】: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


【解决方案1】:

正如@Shannon Severance 所建议的,问题是源表的“ID 序列中的漏洞”。

通过这种方式设置@nextID解决:

SET @nextID = (SELECT MAX(id)+1 FROM dbo.DataHist_2); -- was: SET @nextID = @nextID + @r;

(ID 列已添加到目标表并从 src 复制。)

谢谢你,香农

【讨论】:

    【解决方案2】:

    老兄,@@rowcount 是正确的,总是等于 1。 请检查此代码以获得更清晰的信息:

    -- 将数据从 DataHist 复制到 DataHist_2 /* SRC 表定义: 创建表 [dbo].[#DataHist]( [ID] [BIGINT] IDENTITY(1,1) 非空, [时间戳] [日期时间] 不为空, [NumericID] [INT] 非空, [BadQ] [BIT] NULL 约束 [DF_DataHist_BadQ] 默认(NULL), [质量] AS (CASE ISNULL([BadQ],(0)) WHEN (0) THEN (1) ELSE (0) END), [值] VARCHAR 约束 [PK_DataHist] 主键集群 ( [ID] ASC ) )

                --SELECT * FROM [#DataHist]
                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    #DataHist DH
                                WHERE   NOT EXISTS ( SELECT 1
                                                     FROM   #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 #DataHist_2
                                ( TimeStamp ,
                                  NumericID ,
                                  BadQ ,
                                  Value
                                ) 
                                SELECT TOP ( @N )
                                        TimeStamp ,
                                        NumericID ,
                                        BadQ ,
                                        Value
                                FROM    #DataHist 
                                WHERE   ID >= @nextID
                                ORDER BY ID 
    
                        SET @r = @@ROWCOUNT;
                        SELECT @@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;
    

    【讨论】:

    • 老兄,如果语句触发了触发器,@@rowcount 就会出错。 social.msdn.microsoft.com/Forums/en-US/…
    • 不,@@rowcount 主要是 = 插入的行数,但并非总是如此。这是一个问题。没有触发器。
    • 你的答案是什么?我看到很多代码,但不知道你想用它说什么。
    • @Shannon:如果你检查代码,我只是选择'SELECT @@ROWCOUNT'来证明@@RowCOUNT的值每次都是一样的。
    猜你喜欢
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 2018-11-22
    • 2015-06-14
    相关资源
    最近更新 更多