2014-11-12 2 views
0

Я получаю таблицу строк 6 М, которую нужно отправлять на другой сервер каждый день. это кажется, никогда не закончить, когда я сделать тестирование на:Передача данных вставляет в кусок по 10 000 строк каждый раз

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** 

В противном случае я буду писать цикл.

+0

Я бы написал указатель. Или сделайте это [программно] (https://www.nuget.org/packages/EntityFramework.BulkInsert-ef6/). – abatishchev

+0

Плохая идея использовать курсор 90% времени. – SubqueryCrunch

+0

Если ваше лицензирование SQL Server позволяет вам установить Integration Service, вы можете использовать его. Назначения могут быть просто сконфигурированы с помощью кусков. –

ответ

0

6 миллионов строк в одной транзакции - это довольно значительный фрагмент, и инструкции DML на связанных серверах тоже не велики. Но два способа рассмотреть (которые работали для меня), являются:

  1. Если есть простой способ, чтобы скопировать их в порядке (например, поле ID), то вы можете:

    • Keep трек последнего ID отправленного в новой таблице на ServerB
    • Написать прок на ServerB, что делает цикл, подобный следующему:

      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 - [dbName]. [Dbo] .Table1_ImportFromServerB - который принимает входной параметр NVARCHAR (MAX), преобразует его в XML и делает INSERT INTO Table1 SELECT ... FROM (either @XMLvariable.Nodes or OPENXML)
    • Отправка пакета, завернутого как XML, в сохраненный proc поверх Linked Server является гораздо быстрее, чем делать прямой INSERT над Linked Server
    • Вы должны отправить XML как NVARCHAR (MAX) в XML не допускается для отправки через Связанный сервер
    • таблица [ProcessStatus] это просто отслеживать текущую позицию в случае сбоя процесса и, следовательно, он может начинаться с того места, где он был остановлен, или вы даже можете установить ограничение по времени или счетчик итераций X и запланировать выполнение из задания агента SQL каждые N минут или около того (чтокак я всегда это делал).


  2. Используйте SQLCLR, чтобы использовать SqlBulkCopy класса, который предназначен для данного типа задач. Это по сути тот же API, который используется BCP, OPENROWSET (BULK ...) и BULK INSERT. Вы можете написать свою собственную хранимую процедуру на основе CLR, либо она уже сделана и доступна бесплатно в библиотеке SQL# (которой я являюсь автором, но опять же, она бесплатна). Хранимая процедура называется DB_BulkCopy и позволяет установить размер партии.