SQL Server DELETE медленнее с индексами - PullRequest
6 голосов
/ 11 августа 2010

У меня есть база данных SQL Server 2005, и я попытался поместить индексы в соответствующие поля, чтобы ускорить DELETE записей из таблицы с миллионами строк (big_table имеет только 3 столбца), но теперьDELETE время выполнения даже больше !(Например, 1 час против 13 минут)

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

DELETE FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)

Кстати, я также пробовал:

DELETE FROM big_table
WHERE EXISTS
(SELECT 1 FROM small_table
WHERE small_table.id_product = big_table.id_product
AND small_table.id_category = 1)

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

Я создал индексы для этих полей:

  1. big_table.id_product
  2. small_table.id_product
  3. small_table.id_category

Мой файл .ldf сильно увеличивается во время DELETE.

Почему мои DELETE запросы медленнее, когда у меня есть индексы в моих таблицах? Я думал, что они должны былиработать быстрее.

ОБНОВЛЕНИЕ

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

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

Odetocode.com говорит:

"Индексы работают так же хорошо, когдапоиск записи в командах DELETE и UPDATE так же, как и для операторов SELECT. "

Но далее в статье говорится, что слишком большое количество индексов может снизить производительность.

Ответы на bobs Вопросы:

  1. 55 миллионов строк в таблице
  2. 42 миллиона строк удаляются
  3. Подобный оператор SELECT не будет выполняться (исключение типа 'System.OutOfMemoryException 'было сгенерировано)

Я пробовал следующие 2 запроса:

SELECT * FROM big_table
WHERE big_table.id_product IN (
SELECT small_table.id_product FROM small_table
WHERE small_table.id_category = 1)

SELECT * FROM big_table
INNER JOIN small_table
ON small_table.id_product = big_table.id_product
WHERE small_table.id_category = 1

Оба не удалось после запуска в течение 25 мин с этим сообщением об ошибке из SQL Server 2005:

An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown.

ДатаСервер abase - это старая двухъядерная машина Xeon с оперативной памятью 7,5 ГБ.Это моя тестовая база данных :), так что больше ничего не запускается.

Нужно ли делать что-то особенное с моими индексами после того, как я CREATE сделаю так, чтобы они работали должным образом?

Ответы [ 5 ]

27 голосов
/ 11 августа 2010

Индексы ускоряют поиск - как индекс в конце книги.

Операции, которые изменяют данные (например, УДАЛЕНИЕ), выполняются медленнее, поскольку включают манипулирование индексами.Рассмотрим тот же индекс в конце книги.У вас есть больше работы, если вы добавляете, удаляете или меняете страницы, потому что вам также необходимо обновить индекс.

2 голосов
/ 11 августа 2010

Я согласен с комментарием Бобса выше - если вы удаляете большие объемы данных из больших таблиц, удаление индексов может занять некоторое время, прежде чем удаление данных будет стоить ведения бизнеса.Поскольку он удаляет все данные, вы вызываете события переиндексации.

Что касается роста файла журнала;если вы ничего не делаете со своими лог-файлами, вы можете переключиться на Simple logging;но я настоятельно призываю вас ознакомиться с тем, какое влияние это может оказать на ваш ИТ-отдел до того, как вы начнете меняться.

Если вам необходимо выполнить удаление в режиме реального времени;часто бывает неплохо обходить пометку данных как неактивных либо непосредственно в таблице, либо в другой таблице и исключать эти данные из запросов;затем вернитесь позже и удалите данные, когда пользователи не смотрят на песочные часы.Есть вторая причина для покрытия этого;если вы удаляете много данных из таблицы (что, как я полагаю, основано на проблеме вашего файла журнала), вы, вероятно, захотите выполнить indexdefrag, чтобы повторно зарегистрировать индекс;если вы не любите пользователей по телефону, это может быть сделано в нерабочее время!

1 голос
/ 25 марта 2013

JohnB удаляет около 75% данных. Я думаю, что следующее было бы возможным решением и, возможно, одним из более быстрых. Вместо удаления данных создайте новую таблицу и вставьте данные, которые нужно сохранить. Создайте индексы для этой новой таблицы после вставки данных. Теперь удалите старую таблицу и переименуйте новую в то же имя, что и старая.

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

0 голосов
/ 14 января 2015

Попробуйте что-то подобное, чтобы избежать массового удаления (и тем самым избежать роста файла журнала)

declare @continue bit = 1

-- delete all ids not between starting and ending ids
while @continue = 1
begin

    set @continue = 0

    delete top (10000) u
    from    <tablename> u WITH (READPAST)
    where   <condition>

    if @@ROWCOUNT > 0
        set @continue = 1 

end
0 голосов
/ 11 августа 2010

Вы также можете попробовать расширение TSQL до синтаксиса DELETE и проверить, улучшает ли оно производительность:

DELETE FROM big_table
FROM big_table AS b
INNER JOIN small_table AS s ON (s.id_product = b.id_product)
WHERE s.id_category  =1
...