Оптимизировать обновление sql - PullRequest
0 голосов
/ 06 февраля 2009

У нас есть 2 таблицы с именами TableToUpdate и Даты . Нам необходимо обновить столбец EndTimeKey TableToUpdate , посмотрев из другой таблицы Даты . Мы запускаем sql ниже, чтобы сделать это, но требуется много времени, чтобы закончить.

Таблица TableToUpdate имеет 6M записей. Таблица Даты содержит 5000 записей.

Как мы можем оптимизировать это?

Спасибо за ответы!

update TableToUpdate set
EndTimeKey = DATE_NO
from Dates where EndTime = DATE

Ответы [ 4 ]

2 голосов
/ 06 февраля 2009

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

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

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

Также вот кое-что, что я хотел бы добавить (я также изменил это, показ явно показывать соединение)

update t
set EndTimeKey = DATE_NO
from TableToUpdate t
Join Dates D on t.EndTime = d.DATE
where EndTimeKey <> DATE_NO

Нет смысла обновлять записи, которые уже совпадают.

1 голос
/ 06 февраля 2009

При таком объеме данных вам лучше всего создать запрос SELECT, который выдает набор результатов, дополненный обновленными значениями, как вы хотели бы видеть новую таблицу. Затем, ВЫБЕРИТЕ их в новую таблицу (возможно, «NewTableToUpdate»), либо создав таблицу и используя INSERT INTO, либо изменив свой SELECT, добавив INTO для создания новой таблицы.

Затем используйте sp_rename, чтобы переименовать «TableToUpdate» в «OLDTableToUpdate» и «NEWTableToUpdate» в «TableToUpdate», а затем создать индексы в том виде, в каком они были в исходной таблице.

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

Дополнительные мысли ... если у вас есть кластеризованный индекс в вашей таблице, то добавьте ORDER BY в вашу инструкцию SELECT, чтобы убедиться, что он вставлен в новую таблицу в той же последовательности, что и кластеризованный индекс. Это значительно ускорит создание индекса.

0 голосов
/ 06 февраля 2009

Я отмечу пару вещей здесь, действительно ли EndTimeKey является ключевым? Если это так, у него может быть индекс на нем, в этом случае скорость (или его отсутствие) будет обновлять индекс, в то время как также выполняется фактическое обновление данных, решение удаляет индекс, запускает обновление, повторно применяет индекс. *

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

update TableToUpdate setEndTimeKey = DATE_NOfrom Dates where EndTime = DATE
where TableToUpdateId between 1 and 100000

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

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

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

0 голосов
/ 06 февраля 2009

Вы можете установить некоторые индексы в соответствующих полях (в соответствующем порядке), т.е. endtimekey и endtime. не ожидайте многого из этого. и еще одна вещь, которую вы можете проверить, есть ли у вас другие ограничения для ограничения результатов запроса.

Вы также можете создать представление, которое возвращает для каждого tabletoupdate.endtimekey правильный date_no.

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

...