SQL 服务器:为什么在插入分块时此逻辑不起作用?

SQL Server: Why isn't this logic working when Chunking on inserts?

技术同仁--

我这里发生了无限循环情况。为什么@@rowcount 永远不会设置回 0?我一定没有理解 @@rowcount 的真正作用——或者我在错误的地方设置了值。我认为每次通过时该值都应该递减,直到我最终达到零。

 DECLARE @ChunkSize int = 250000;

 WHILE @ChunkSize <> 0
 BEGIN
    BEGIN TRANSACTION

     INSERT TableName
      (col1,col2)
     SELECT TOP (@ChunkSize)
      col1,col2
     FROM TableName2

    COMMIT TRANSACTION;

    SET @ChunkSize = @@ROWCOUNT

   END -- transaction block

 END -- while-loop block

根据您发布的内容,我不确定您将如何确保捕获尚未插入的行。如果你不这样做,那当然是一个无限循环。这是一种使用测试数据的方法——但您自然希望它基于 PK 或其他独特的列。也许你只是把那部分遗漏了,或者我遗漏了一些东西。我只是对您的分块最终代码及其背后的逻辑感兴趣,所以这是一个答案和询问。

if object_id('tempdb..#source') is not null drop table #source
if object_id('tempdb..#destination') is not null drop table #destination

create table #source(c1 int, c2 int)
create table #destination (c1 int, c2 int)

insert into #source (c1,c2) values
(1,1),
(2,1),
(3,1),
(4,1),
(5,1),
(6,1),
(7,1),
(8,1),
(9,1),
(10,1),
(11,1),
(12,1)


 DECLARE @ChunkSize int = 2;

 WHILE @ChunkSize <> 0
 BEGIN

        INSERT INTO #destination (c1,c2)
        SELECT TOP (@ChunkSize) c1,c2 FROM #source WHERE c1 NOT IN (SELECT DISTINCT c1 FROM #destination) ORDER BY ROW_NUMBER() OVER (ORDER BY C1)
        SET @ChunkSize = @@ROWCOUNT

    --SELECT @ChunkSize
 END 

 select * from #source
 select * from #destination

没有发生任何事情,因为您将 chunksize 设置为自身,而没有查看您已经插入的内容。使用您的示例,@Chunksize = 250000。首先,select 执行 SELECT TOP 250000 和 returns(大概)250000 行。然后您使用 @@RowCount 更新 @Chunksize,但返回的行数将为 250000,因此您只需再次将其设置为 250000。这可能没问题,除了如果不排除您已经插入的行,数字永远不会改变 - 您将一遍又一遍地插入相同的 250000 行。

您需要 NOT EXISTS 之类的东西来过滤掉您已经插入的行:

DECLARE @ChunkSize int = 250000;

WHILE @ChunkSize > 0
BEGIN
  BEGIN TRANSACTION

   INSERT INTO TableName
    (col1,col2)
   SELECT TOP (@ChunkSize)
    col1,col2
   FROM TableName2 T2
   WHERE NOT EXISTS (SELECT *
                     FROM   TableName T
                     WHERE  T.Col1 = T2.Col1
                     AND    T.Col2 = T2.Col2)

  SET @ChunkSize = @@ROWCOUNT
  PRINT CONVERT(nvarchar(10),@ChunkSize) + ' Rows Inserted.';

  COMMIT TRANSACTION

END -- while-loop block

已实施解决方案

最后,我决定通过 SSIS 抽取 SQL,在那里我可以相应地设置提交批大小。如果我没有选择 hat route,我将不得不遵循 @scsimon 的建议并基本上保持跟踪 table 完成的记录和剩下的记录循环。