ОБНОВЛЕНИЕ с JOIN на 100 мм записи, как это сделать лучше? (в T-SQL)

11

Мне нужно обновить 100 миллионов записей в одной таблице, по сути, нормализуя таблицу, заменив значение столбца varchar просто идентификатором. (Я говорю «замена», но на самом деле я пишу идентификатор в другой столбец.)

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

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

Фон

  • использование MSSQL 2008 R2 на сервере 2008 R2
  • сервер имеет 8 ГБ оперативной памяти
  • на сервере есть один RAID10, 7200 об / мин SATA (я знаю, что в производственном режиме это будет только чтение данных, а не запись данных; плюс недавний дефицит HD сделал это необходимым по стоимости)
  • сервер имеет двойной четырехъядерный процессор Xeon
  • машина больше ничего не делает (в данный момент посвящена dev, только этот процесс)
  • включено простое ведение журнала (? - но оно все еще регистрируется, чтобы можно было выполнить откат?)
  • обратите внимание, что запрос ссылается на две разные БД, для чего это стоит
  • «ширина» обновляемой записи в таблице составляет 455 байт

Ресурсы во время исполнения

  • физическое ОЗУ максимально
  • дисковый ввод / вывод максимально
  • Процессор почти ничего не делает (точка дросселирования - ввод / вывод)
  • Время работы составило 14 часов и считал!

Я подозреваю несколько вещей, например, мне нужен индекс для необработанных данных, хотя я буду отбрасывать столбец (AutoClassName) после обновления нормализации. Мне также интересно, должен ли я просто зацикливать таблицу по одной записи за раз вместо JOIN, что казалось нелепым в то время, когда я начинал это, но теперь кажется, что это было бы быстрее.

Как мне изменить мою методологию для оставшихся обновлений нормализации (аналогично этой) быстрее?

Крис Адранья
источник

Ответы:

7

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

Вы также выиграете от:

  • Временный индекс для AutoData.dbo.AutoClass.AutoClassName
  • Больше оперативной памяти Лота больше оперативной памяти.
Марк Стори-Смит
источник
1
+1 Я согласен с пакетным обновлением, используя TOPпункт. Это был бы мой подход.
Томас Стрингер
Если я выполню UPDATE TOP, тогда мне понадобится предложение WHERE (WHERE AutoClassID равно NULL)? Не будет ли предложение WHERE вводить новый удар по производительности (сканирование таблицы, которым я сейчас не занимаюсь). Без сомнения, это уменьшит проблему с оперативной памятью, которую я испытываю с JOIN.
Крис Адранья
Мой ответ давно назрел, но в моем случае SET ROWCOUNT оказался наиболее эффективным.
Крис Адранья
10

Я бы выбрал другой подход.

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

Это почти наверняка будет быстрее:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

В настоящее время написано много логических операций:

  • Прочитать все значения A.AutoClassName
  • Прочитать все значения B.AutoClassName
  • Сравните значения A и B
  • Из соответствующего набора прочитайте все значения B.AutoClassID
  • Обновите существующие значения A.AutoClassId, чтобы они стали значением B.AutoClassId через все существующие индексы.
JNK
источник
Это звучит как хороший, простой подход, особенно учитывая проблему с дисковым вводом / выводом, которая у меня возникла. Спасибо за быстрый ответ.
Крис Адранья
1
Я предлагаю вам еще раз проверить, достаточно ли у вас свободного места в журнале и файлах данных. Если файлы автоматически растут, производительность резко упадет. Я часто вижу, как люди запускают какие-то большие одноразовые обновления и автоматически увеличивают свой лог-файл, даже не осознавая этого.
пролив
5

Зацикливание таблицы по одной строке за раз, не будет быстрее!

Как вы подозреваете и подтверждаете вы, это будет связано с вводом / выводом - один диск, чтение, запись, журналы транзакций и (любое) временное рабочее пространство будут конкурировать за один и тот же ввод / вывод.

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

Вы пробовали индексировать поле AutoClassName? Сколько существует различных значений автокласса?

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

Кев Райли
источник
Существует только 15 различных значений автокласса. Ваши комментарии подтверждают многие мои подозрения (и боли!). Спасибо, что ответили.
Крис Адранья
3

Создайте индексы для полей объединения.

Вы всегда можете удалить индексы, когда вы закончите.

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

Джимбо
источник
Я уверен, что показатели улучшатся. Я предполагаю, что вопрос состоит в том, улучшаются ли они больше, чем время, необходимое для создания индекса (только для одного использования). Возможно - да. :)
Крис Адранья
3

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

srini.venigalla
источник