2010-08-10 4 views
5

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

У меня есть отношение между таблицами, а столбец, который я фильтрую, 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) 

Btw, я также пытался:

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 медленнее, когда у меня есть индексы на моих таблицах? Я думал, что они должны бежать быстрее.

UPDATE

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

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

Odetocode.com says:

«Индексы работают точно так же при поиске записи в DELETE и UPDATE команд, как они делают для ЗЕЬЕСТА.»

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

Ответы на качается вопросы:

  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. 

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

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

+3

Сколько строк в таблице? Сколько строк удаляется? Как долго будет выполняться аналогичная инструкция SELECT? Знание того, как быстро выполняется инструкция SELECT, может дать некоторое представление о том, как индексы влияют на DELETE. – bobs

+0

55 mil rows, 42 deleted, не завершено, см. Выше для получения более подробной информации. – JohnB

+0

Это занимает больше времени, потому что, когда вы выполняете удаление, индексы, которые ссылаются на вашу таблицу, также должны быть обновлены. – WOPR

ответ

27

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

Операции, которые изменяют данные (например, DELETE), медленнее, поскольку они включают в себя манипулирование индексами. Рассмотрим тот же самый индекс в конце книги. У вас есть больше работы, если вы добавляете, удаляете или меняете страницы, потому что вам нужно также обновить индекс.

0

Вы также можете попробовать расширение TSQL УДАЛИТЬ синтаксис и проверить, улучшает ли это производительность:

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 
+0

Это не помогло; он занял то же время, что и «delete from big_table where exists» (выберите 1 из small_table, где small_table.id_product = big_table.id_product и small_table.id_category = 1) ' – JohnB

1

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

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

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

0

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

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

0

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

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 
Смежные вопросы