2013-06-07 3 views
1

У нас есть 2 таблицы в SQL Server 2008 R2. Периодически мы должны вставлять партию записей из таблицы A в таблицу B. В то время как вставка, таблица B все еще способна SELECT & UPDATE. В настоящее время мы используем INSERT..SELECT для копирования из таблицы A в таблицу B. Но проблема заключается во вставке, иногда это приведет к тому, что инструкция UPDATE будет табуляции TABLE B.Массовая вставка из таблицы в другую

Есть ли лучшее решение для вставки вставки из таблицы в другую, что не приведет к блокировке?

+0

вы можете запускать обновление в меньших партиях, например, используя «update top (5000) ...» в цикле – Stanley

+0

Я думаю, что вы имеете в виду вставку меньшими партиями. Хорошая идея. Но тогда нам нужно отслеживать, какая запись была скопирована для предотвращения дублирования в ТАБЛИЦЕ B. – kevin

ответ

0

1 Установите тайм-аут транзакции на достаточно большое значение, чтобы оператор больше не перешел в таймаут.

2 С помощью кнопок курсора и сделать его строка за строкой

3 Попробуйте этот способ делать вещи. Требуется идентификатор строки (IDENTITY, например), лучше иметь ПК или INDEX на этом поле:

SET NOCOUNT ON; 

CREATE TABLE #A(
    row_id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    data INT NOT NULL 
); 

CREATE TABLE #B(
    row_id INT NOT NULL PRIMARY KEY, 
    data INT NOT NULL 
); 

-- TRUNCATE TABLE #B; -- no truncate needed since you just want to add rows, not copy the whole table 

DECLARE @batch_size INT; 
SET @batch_size = 10000; 

DECLARE @from_row_id INT; 
DECLARE @to_row_id INT; 

-- You would use this to establish the first @from_row_id if you wanted to copy the whole table 
-- SELECT 
-- @from_row_id=ISNULL(MIN(row_id),-1) 
-- FROM 
-- #A AS a; 

SELECT 
    @from_row_id=ISNULL(MAX(row_id),-1) 
FROM 
    #B AS b; 

IF @from_row_id=-1 
    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a; 
ELSE 
    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a 
    WHERE 
     row_id>@from_row_id; 

WHILE @from_row_id>=0 
BEGIN 
    SELECT 
     @to_row_id=ISNULL(MAX(row_id),-1) 
    FROM 
     (
      SELECT TOP(@batch_size) 
       row_id 
      FROM 
       #A AS a 
      WHERE 
       row_id>[email protected]_row_id 
     ) AS row_ids 

    IF @to_row_id=-1 
    BEGIN 
     INSERT 
      #B 
     SELECT 
      * 
     FROM 
      #A AS a 
     WHERE 
      row_id>[email protected]_row_id; 

     BREAK; 
    END 
    ELSE 
     INSERT 
      #B 
     SELECT 
      * 
     FROM 
      #A AS a 
     WHERE 
      row_id BETWEEN @from_row_id AND @to_row_id; 

    SELECT 
     @from_row_id=ISNULL(MIN(row_id),-1) 
    FROM 
     #A AS a 
    WHERE 
     row_id>@to_row_id; 
END 

DROP TABLE #B; 
DROP TABLE #A; 
+0

Спасибо. Необходимо протестировать вариант 2 и 3. Время, затрачиваемое на вставку полной партии VS приемлемой продолжительности блокировки. – kevin

+0

@kevin Я бы выбрал вариант 3 перед вариантом 2, используя CURSOR, было бы менее эффективно в целом, так как вы скопировали бы строку за строкой, а не вставляли в объем, как в варианте 3. Если вы найдете скрипт полезным, пожалуйста, повысьте и/или отметьте метку «решение». –

0

Они наиболее очевидным решением является использование более мелких партий, как предложил Стэнли. Если это действительно не вариант, вы можете исследовать '(transaction level) snapshot isolation.

+0

Yup. Пока что предложение от Стэнли и Вариант 3 от ТТ самые эффективные сейчас. – kevin

Смежные вопросы