2016-01-19 2 views
2

Как я могу ускорить этот довольно простой запрос UPDATE? Он работает более 5 часов!Как ускорить простой запрос UPDATE с миллионами строк?

Я в основном заменяю SourceID в таблице, присоединяясь к новой таблице с старыми и новыми идентификаторами. Все эти поля - VARCHAR (72) и должны оставаться такими.

Таблица Pub_ArticleFaculty содержит 8 354 474 строки (8,3 млн.). ArticleAuthorOldNew имеет 99,326,472 строки (99,3 миллиона) и только 2 поля, которые вы видите ниже.

На всех этих полях имеются отдельные некластеризованные индексы. Есть ли лучший способ написать этот запрос, чтобы он работал быстрее?

UPDATE PF 
     SET PF.SourceId = AAON.NewSourceId 
    FROM AA..Pub_ArticleFaculty PF WITH (NOLOCK) 
     INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
        ON AAON.OldFullSourceId = PF.SourceId 
+0

После того, как он закончил, вы когда-нибудь придется сделать это снова? –

+0

Какой режим восстановления является вашей базой данных в (ПОЛНЫЙ, ПРОСТОЙ, БОЛЬШОЙ-ЛОГИРОВАННЫЙ)? Правильно ли размер журнала транзакций? –

+0

Эта база данных находится в режиме полного восстановления. Это нормально, чтобы вылететь на час или около того, может быть, так как он находится в тестовой среде. Мне не придется запускать это снова, и я не уверен, как определить, соответствует ли журнал надлежащим образом. Я даже не забочусь о регистрации, поскольку при необходимости у нас есть резервная копия БД. – Andy

ответ

1

По моему опыту, зацикливание вашего обновления так, чтобы оно действовало на небольшом количестве строк, каждая итерация - хороший способ пойти.Идеальное количество строк для обновления каждой итерации во многом зависит от вашей среды и таблиц, с которыми вы работаете. Обычно я придерживаюсь 1000 - 10 000 строк за итерацию.

Пример

SET ROWCOUNT 1000 -- Set the batch size (number of rows to affect each time through the loop). 
WHILE (1=1) BEGIN 

    UPDATE PF 
    SET NewSourceId = 1 
    FROM AA..Pub_ArticleFaculty PF WITH (NOLOCK) 
      INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
         ON AAON.OldFullSourceId = PF.SourceId 
    WHERE NewSourceId IS NULL -- Only update rows that haven't yet been updated. 

    -- When no rows are affected, we're done! 
    IF @@ROWCOUNT = 0 
     BREAK 
END 
SET ROWCOUNT 0 -- Reset the batch size to the default (i.e. all rows). 
GO 
2

Если сброс всех или почти всех значений, то update будет довольно дорого. Это связано с протоколированием и накладными расходами на обновления.

Один подход можно взять вместо этого insert во временную таблицу, а затем обрезает, а затем повторно вставить:

select pf.col1, pf.col2, . . . , 
     coalesce(aaon.NewSourceId, pf.sourceid) as SourceId 
into temp_pf 
from AA..Pub_ArticleFaculty PF LEFT JOIN 
    AA2..ArticleAuthorOldNew AAON 
    on AAON.OldFullSourceId = PF.SourceId; 

truncate table AA..Pub_ArticleFaculty; 

insert into AA..Pub_ArticleFaculty 
    select * from temp_pf; 

Примечание: Вы должны либо быть уверены, что столбцы в исходной таблице соответствует временной таблицы или, еще лучше, перечислить столбцы явно в insert.

Следует также отметить, что основным преимуществом является то, что ваш режим восстановления прост или зарегистрирован в большом количестве. Причина в том, что каротаж для усечения, select into и insert . . . select минимален (см. here). Эта экономия на лесозаготовках может быть очень значительной.

+1

будет использовать режим ВОССТАНОВЛЕННОГО РЕГИСТРАЦИИ, чтобы уменьшить я могу попробовать этот подход, о котором вы упомянули, но не уверен, что я чувствую себя хорошо об усечении стола, поскольку у него более 30 полей (не мой дизайн, жаль на меня ... ха-ха!). Слишком много места для ошибок, Я думаю, что – Andy

+0

@AndyDesRosiers ... Вы можете поместить данные во временную таблицу, а затем переименовать таблицы вместо того, чтобы вставлять значения обратно. Этот шаг предназначен для сохранения ограничений, триггеров и т. Д. –

0

У меня недостаточно баллов, чтобы прокомментировать вопрос. Поэтому я добавляю его в качестве ответа. Вы можете проверить базовые

  1. Любые триггеры за столом? Если это так, что вы будете бить столько раз, сколько обновляете строки. Если есть такая цепочка, это будет причиной снижения производительности.

  2. Есть ли индексы на соединительных колоннах?

  3. В других случаях система работает хорошо? Проверка системы имеет достаточную мощность

Но 8 миллионов записей не могут превышать 1 минуту при правильной обработке. 5 часов означает, что некоторые, где еще проблема

1

Я

  • Отключение индекса на PF.SourceId
  • Выполнить обновление
  • Затем перестроить индекс

Я не» t получите NOLOCK на таблице, которую вы обновляете

UPDATE PF 
SET PF.SourceId = AAON.NewSourceId 
FROM AA..Pub_ArticleFaculty PF 
INNER JOIN AA2..ArticleAuthorOldNew AAON WITH (NOLOCK) 
     ON AAON.OldFullSourceId = PF.SourceId 
     AND PF.SourceId <> AAON.NewSourceId 
+0

Я взял от NOLOCK сейчас, а также cha чтобы база выполнялась в режиме полного восстановления SIMPLE временно, а также добавляла предложение WHERE LIKE для запуска данных в кусках в отдельных запросах. Похоже, что это ускорило его. Мне любопытно отключить индекс, хотя ... Я думал, что цель этого заключалась в том, чтобы ускорить поиск и присоединение? Но разве это потому, что мы обновляем это поле, что он заставляет вещи работать медленнее с индексом? – Andy

+0

Обслуживание индекса требует времени. Что больно попробовать? – Paparazzi

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