Обновление или слияние очень больших таблиц в SQL Server

мне нужно выполнить ежедневное обновление очень больших (300M записей) и широких TABLE1. Исходные данные для обновлений находятся в другой таблице UTABLE это 10%-25% строк TABLE1 но узкая. Обе таблицы имеют record_id в качестве первичного ключа.

в настоящее время, я воссоздаю TABLE1 использовать следующий подход:

<!-- language: sql -->
    1) SELECT (required columns) INTO TMP_TABLE1 
    FROM TABLE1 T join UTABLE U on T.record_id=U.record_id  
    2) DROP TABLE TABLE1  
    3) sp_rename 'TMP_TABLE1', 'TABLE1'

однако это занимает почти 40 минут на моем сервере (60 ГБ ОЗУ для SQL Server). Я хочу достичь производительности 50% выгоды - какие еще варианты можно попробовать?

  1. MERGE и UPDATE - что-то вроде кода ниже работает быстрее только для очень маленького UTABLE таблица-в полном размере, все просто висит:

    <!-- language: SQL -->
    MERGE TABLE1 as target  
    USING UTABLE as source  
    ON target.record_id = source.record_id   
      WHEN MATCHED THEN   
        UPDATE SET Target.columns=source.columns
    
  2. Я слышал, что могу выполнить пакетное слияние с помощью ROWCOUNT - но я не думаю, что это может быть достаточно быстро для таблицы строк 300M.

  3. любые подсказки SQL-запросов, которые могут быть полезны?

2 ответов


на самом деле я узнал общие рекомендации для таких запросов: идея использовать слияние или обновление SQL очень умная, но она терпит неудачу, когда нам нужно обновить много записей (т. е. 75M) в большой и широкой таблице (т. е. 240M).

глядя на план запроса запроса ниже мы можем сказать, что TABLE SCAN таблицы 1 и final MERGE занимают 90% времени.

MERGE TABLE1 as Target  
USING UTABLE as source  
ON Target.record_id = source.record_id   
WHEN MATCHED AND (condition) THEN   
    UPDATE SET Target.columns=source.columns

поэтому для использования MERGE нам нужно:

  1. уменьшите количество строк, которые нам нужно обновить, и правильно передайте эту информацию SQL Server. Это можно сделать, сделав UTABLE меньше или указание дополнительных condition это сужает часть, которая должна быть объединена.
  2. убедитесь, что часть, подлежащая объединению, помещается в память, иначе запрос выполняется медленнее. Делая TABLE1 в два раза меньше уменьшило мое реальное время запроса с 11 часов до 40 минут.

как отметил Марк, вы можете использовать UPDATE синтаксис и использование WHERE предложение для сужения части, подлежащей объединению - это даст те же результаты. Также, пожалуйста, избегайте индексирования TABLE1 поскольку это приведет к дополнительной работе по перестроению индекса во время MERGE


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

воссоздание полной таблицы-это большая загрузка ввода-вывода, не говоря уже о том, что это займет много места, чтобы в основном сохранить таблицу дважды временно.

вам нужно выполнить слияние - из того, что я вижу, достаточно простого обновления. Пример:

UPDATE
    TABLE1
SET
    ColumnX = UTABLE.ColumnX
    ...
FROM
    TABLE1
INNER JOIN
    UTABLE ON TABLE1.record_id = UTABLE.record_id

вы можете пакетировать обновления, используя ROWCOUNT, но это не ускорит выполнение, это поможет только уменьшить общую блокировку.

также - какие индексы у вас есть на столе? Возможно, быстрее отключить индексы перед обновлением, а затем перестроить их с нуля (только некластеризованные).