Самый быстрый способ сделать массовое обновление

Скажем, у Вас есть таблица приблизительно с 5 миллионами записей и a nvarchar(max) столбец заполняется с данными крупного текста. Вы хотите установить этот столбец на NULL если SomeOtherColumn = 1 самым быстрым способом.

Грубая сила UPDATE не работает очень хорошо здесь, потому что это создаст большую неявную транзакцию и возьмет навсегда.

Выполнение обновлений в маленьких пакетах 50K записывает в повременные работы, но все еще требуется 47 часов для завершения на раскормленных 32 core/64GB серверах.

Там какой-либо путь состоит в том, чтобы сделать это обновление быстрее? Есть ли какие-либо волшебные подсказки запроса / опции таблицы, который жертвует чем-то еще (как параллелизм) в обмен на скорость?

Примечание: Составление временной таблицы или временного столбца не является опцией потому что это nvarchar(max) столбец включает много данных и так занимает много места!

PS: да, SomeOtherColumn уже индексируется.

16
задан David Tansey 18 August 2016 в 02:30
поделиться

7 ответов

Надеюсь, вы уже сбросили все индексы для столбца, для которого задается значение NULL, включая полнотекстовые индексы. Как было сказано ранее, временное отключение транзакций и файла журнала поможет. Резервное копирование данных обычно приводит к усечению и файлов журнала.

4
ответ дан 30 November 2019 в 22:37
поделиться

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

Какие индексы установлены в таблице? Учитывая, что пакетные обновления примерно 50 000 строк занимают так много времени, я бы сказал, что вам нужен индекс.

3
ответ дан 30 November 2019 в 22:37
поделиться

Пробовали ли вы поместить индекс или статистику в someOtherColumn?

1
ответ дан 30 November 2019 в 22:37
поделиться

Это мне очень помогло. С этим я ушел с 2 часов до 20 минут.

/* I'm using database recovery mode to Simple */
/* Update table statistics */

set transaction isolation level read uncommitted     

/* Your 50k update, just to have a measures of the time it will take */

set transaction isolation level READ COMMITTED

По моему опыту, работая в MSSQL 2005, ежедневное (автоматическое) перемещение 4 миллионов 46-байтовых записей (без nvarchar (макс.)) Из одной таблицы в базе данных в другую таблицу в другой базе данных занимает около 20 минут. сервер QuadCore 8 ГБ, 2 ГГц, и это не снижает производительности приложений. Под перемещением я подразумеваю INSERT INTO SELECT, а затем DELETE. Использование ЦП никогда не превышает 30%, даже когда удаляемая таблица имеет 28 миллионов записей и постоянно делает около 4 КБ вставок в минуту, но без обновлений. Ну, это мой случай, это может варьироваться в зависимости от загрузки вашего сервера.

READ UNCOMMITTED

«Указывает, что операторы (ваши обновления) могут читать строки, которые были изменены другими транзакциями, но еще не зафиксированы». В моем случае записи доступны только для чтения.

Я не знаю, что означает rg-tsql, но здесь вы найдете информацию об уровнях изоляции транзакций в MSSQL.

1
ответ дан 30 November 2019 в 22:37
поделиться

Попробуйте проиндексировать SomeOtherColumn ... 50 КБ записей должны обновиться мгновенно. Если индекс уже существует, посмотрите, нужно ли его реорганизовать и что для него собрана статистика.

0
ответ дан 30 November 2019 в 22:37
поделиться

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

Если вы предоставите некоторую информацию о количестве строк с SomeOtherColumn = 1, возможно, мы можем подумать иначе, но я предлагаю:

0) Сделайте резервную копию вашей таблицы 1) Индексируйте столбец флагов 2) Установите для параметра таблицы значение "без транзакций журнала" ... если возможно 3) напишите хранимую процедуру для запуска обновлений

0
ответ дан 30 November 2019 в 22:37
поделиться

Судя по всему, не похоже, что ваши проблемы связаны с индексами.

Ключ, похоже, в том, что ваше поле nvarchar (max) содержит "много" данных. Подумайте, что должен делать SQL, чтобы выполнить это обновление.

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

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

Предполагая (для простоты), что каждый столбец содержит в среднем 10 000 байт данных, это означает, что 50 000 строк будут содержать около 500 МБ данных, которые должны храниться временно (в режиме простого восстановления) или постоянно (в режиме полного восстановления). ).

Невозможно отключить журналы, так как это нарушит целостность базы данных.

Я провел быстрый тест на своем медленном рабочем столе моей собаки, и запуск пакетов даже из 10 000 стал слишком медленным, но уменьшение размера до 1000 строк, что подразумевает временный размер журнала около 10 МБ, сработало просто отлично.

Я загрузил таблицу с 350 000 строками и пометил 50 000 из них для обновления.Это завершилось примерно за 4 минуты, и, поскольку он масштабируется линейно, вы сможете обновить все свои 5 миллионов строк на моем медленном рабочем столе собаки примерно за 6 часов на моем рабочем столе с 1 процессором 2 ГБ, поэтому я ожидал бы чего-то гораздо лучшего на вашем мощном сервере, поддерживаемом по SAN или что-то в этом роде.

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

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

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

8
ответ дан 30 November 2019 в 22:37
поделиться