数据传输每次插入10,000行的块

时间:2014-11-12 23:57:08

标签: sql sql-server tsql bulkinsert data-transfer

我得到一个6M行表需要每天发送到另一台服务器。 当我通过测试时似乎永远不会完成:

insert into serverA.dbName.dbo.table1
select * from serverB.dbName.dbo.table1

有"每次做10000行"

类似

insert into serverA.dbName.dbo.table1
select * from serverB.dbName.dbo.table1
**by numOfRowEachTime=10000**

否则我会写一个循环。

1 个答案:

答案 0 :(得分:0)

单个事务中的600万行是一个相当大的块,并且链接服务器上的DML语句也不是很好。但是要考虑的两种方法(对我有用)是:

  1. 如果有一种简单的方法可以按顺序复制它们(例如ID字段),那么您可以:

    • 跟踪ServerB上新表中发送的最后一个ID
    • 在ServerB上写一个proc,它执行类似于以下的循环:

      DECLARE @StartingID INT = 1,
              @EndingID INT,
              @DataToTransport NVARCHAR(MAX);
      
      SELECT @StartingID = StartingID FROM dbo.ProcessStatus;
      
      WHILE (1 = 1)
      BEGIN
         ;WITH cte AS
         (
            SELECT TOP (10000) t1.ID,
                   ROW_NUMBER() OVER (ORDER BY t1.ID ASC) AS [RowNum]
            FROM   dbo.Table1 t1
            WHERE t1.ID >= @StartingID
         )
         SELECT TOP (1) @EndingID = cte.[ID] FROM cte
         ORDER BY cte.[RowNum] DESC;
      
         IF (@@ROWCOUNT = 0)
         BEGIN
            UPDATE dbo.ProcessStatus SET StartingID = 1;
            BREAK; -- reset to start at the beginning and exit
         END;
      
         SET @DataToTransport = (CONVERT(NVARCHAR(MAX), (
             SELECT t1.* FROM dbo.Table1 t1
             WHERE t1.ID BETWEEN @StartingID AND @EndingID
             FOR XML RAW));
      
         EXEC [ServerA].[dbName].[dbo].Table1_ImportFromServerB @DataToTransport;
      
         UPDATE dbo.ProcessStatus SET StartingID = @StartingID;
      
         SET @StartingID = (@EndingID + 1);
      END;
      
    • 在ServerA上编写一个proc - [dbName]。[dbo] .Table1_ImportFromServerB - 接受NVARCHAR(MAX)输入参数,将其转换为XML,然后执行INSERT INTO Table1 SELECT ... FROM (either @XMLvariable.Nodes or OPENXML)
    • 通过链接服务器将包装为XML的批处理发送到存储过程比通过链接服务器执行直接INSERT更快
    • 您必须将XML作为NVARCHAR(MAX)发送,因为不允许通过链接服务器发送XML
    • [ProcessStatus]表只是为了跟踪当前位置,以防过程失败,因此它可以从停止的位置开始,或者您甚至可以设置X迭代的时间限制或计数器并安排到每隔N分钟左右从一个SQL代理作业运行(这就是我一直这样做的原因)。


  2. 使用SQLCLR来使用为此类任务设计的SqlBulkCopy类。它本质上与BCP,OPENROWSET(BULK ...)和BULK INSERT使用的API相同。您可以编写自己的基于CLR的存储过程,或者已经在SQL#库(我是其作者,但同样免费)中已经完成并且可以免费获得。存储过程称为DB_BulkCopy,允许设置批量大小。