2010-06-02 2 views
14

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

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

Выполнение обновлений в небольших партиях по 50 тыс. Записей за один раз работает, но по-прежнему занимает 47 часов, чтобы завершить работу на усиленном 32-ядерном/64-Гбайт сервере.

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

ПРИМЕЧАНИЕ. Создание таблицы temp или столбца temp не является вариантом, потому что этот столбец nvarchar(max) включает в себя множество данных и поэтому потребляет много места!

PS: Да, SomeOtherColumn уже проиндексирован.

+0

См. Также: http://stackoverflow.com/questions/571750/make-sql-server-faster-at-manipulating-data-turn-off-transaction-logging –

+0

Как вы делаете «50 тыс. Партийных записей в время "обновления? Это с хранимой процедурой? Если да, можете ли вы поместить код? – Fede

+0

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

ответ

1

Вы пытались поместить индекс или статистику на someOtherColumn?

+0

Если проблема с производительностью связана с отсутствием индекса, и поэтому для определения строк для обновления требуется сканирование таблицы, то не потребуется ли (или больше) для создания нового индекса и последующего обновления? –

+0

Действительно индекс на столбце nvarchar (max)? – Paparazzi

3

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

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

0

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

0

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

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

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

+0

Кстати ... вам нужно будет проходить эту процедуру несколько раз в жизни? –

+1

Как вы устанавливаете параметр таблицы для «no log tranctions»? – user356004

3

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

+0

Определенно убедитесь, что вы отбрасываете индексы. Для меня в прошлом значительно сократилось. –

1

Это действительно помогло мне. Я пошел с 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%, даже когда удаляемая таблица имеет записи 28M, и она постоянно составляет около 4K в минуту, но обновлений нет. Ну, это мое дело, оно может меняться в зависимости от загрузки вашего сервера.

READ UNCOMMITTED

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

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

+1

«rg» - компания RedGate, спонсирующая компанию, которая рекламирует результаты тега [tsql]. – Corey

+1

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

7

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

Ключ, кажется, заключается в том, что ваше поле 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 или что-то в этом роде.

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

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

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

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