Инструкция Delete в SQL очень медленная

у меня есть такие заявления, которые тайм-аут:

DELETE FROM [table] WHERE [COL] IN ( '1', '2', '6', '12', '24', '7', '3', '5')

Я пробовал делать по одному за раз, как это:

DELETE FROM [table] WHERE [COL] IN ( '1' )

и до сих пор это на 22 минутах и все еще идет.

таблица содержит 260 000 строк и состоит из четырех столбцов.

есть ли у кого-нибудь идеи, почему это будет так медленно и как ускорить его? У меня есть не уникальный, некластеризованный индекс на [COL], который я делаю где. Я с помощью SQL Server 2008 с Р2

update: у меня нет триггеров на столе.

11 ответов


вещи, которые могут привести к удалению медленно:

  • удаление большого количества записей
  • много индексов
  • отсутствующие индексы на внешних ключах в дочерних таблицах. (спасибо @CesarAlvaradoDiaz за упоминание об этом в комментариях)
  • блокировки и блокировки
  • триггеры
  • cascade delete (эти десять родительских записей, которые вы удаляете, могут означать миллионы дочерних записей удаляются)
  • журнал транзакций нужно расти
  • многие внешние ключи для проверки

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


  1. отключить ограничение

    ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;

  2. Отключить Индекс

    ALTER INDEX ALL ON [TableName] DISABLE;

  3. Перестроить Индекс

    ALTER INDEX ALL ON [TableName] REBUILD;

  4. включить ограничение

    ALTER TABLE [TableName] CHECK CONSTRAINT ALL;

  5. удалить


удаление многих строк может быть очень медленным. Попробуйте удалить несколько за раз, например:

delete top (10) YourTable where col in ('1','2','3','4')
while @@rowcount > 0
    begin
    delete top (10) YourTable where col in ('1','2','3','4')
    end

Превентивные Действия

проверьте с помощью SQL Profiler для основной причины этой проблемы. Может быть Triggers вызывает задержку выполнения. Это может быть что угодно. Не забудьте выбрать Database Name и Object Name при запуске Trace исключить сканирование ненужных запросов...

Фильтрация Имен Баз Данных

Таблица / Хранимая Процедура / Имя Триггера Фильтрация

Корректирующих Действий

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

Delete K From YourTable1 K
Inner Join YourTable2 T on T.id = K.id

вставить IN Predicate значения в Temporary Table или Local Variable


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

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


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

У меня была ситуация, когда NHibernate неправильно создал дублированный FKs в тех же столбцах, но с разными именами (что разрешено SQL Server). Это резко замедлило выполнение инструкции DELETE.


является ли [COL] действительно символьным полем, содержащим числа, или вы можете избавиться от одинарных кавычек вокруг значений? @Alex прав, что IN медленнее, чем=, поэтому, если вы можете это сделать, вам будет лучше:

DELETE FROM [table] WHERE [COL] = '1'

но еще лучше использовать числа, а не строки, чтобы найти строки (sql любит числа):

 DELETE FROM [table] WHERE [COL] = 1

может попробовать:

 DELETE FROM [table] WHERE CAST([COL] AS INT) = 1

в любом случае убедитесь, что у вас есть индекс в столбце [COL] для ускорения сканирования таблицы.


проверить план выполнения этой инструкции delete. Посмотрите, используется ли index seek. Также что такое тип данных col?

Если вы используете неправильный тип данных, измените инструкцию update (например, с '1'на 1 или N'1').

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


Я прочитал эту статью, это было действительно полезно для устранения любых неудобств

https://support.microsoft.com/en-us/kb/224453

Это случай waitresource Ключ: 16: 72057595075231744 (ab74b4daaf17)

-- First SQL Provider to find the SPID (Session ID)

-- Second Identify problem, check Status, Open_tran, Lastwaittype, waittype, and waittime
-- iMPORTANT Waitresource select * from sys.sysprocesses where spid = 57

select * from sys.databases where database_id=16

-- with Waitresource check this to obtain object id 
select * from sys.partitions where hobt_id=72057595075231744

select * from sys.objects where object_id=2105058535

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


откройте CMD и запустите эту команду

NET STOP MSSQLSERVER
NET START MSSQLSERVER

это перезапустит экземпляр SQL Server. попробуйте запустить еще раз после команды delete

У меня есть эта команда в пакетном скрипте и запускайте ее время от времени, если я сталкиваюсь с такими проблемами. Обычный перезапуск ПК не будет таким же, поэтому перезапуск экземпляра является наиболее эффективным способом, если вы столкнулись с некоторыми проблемами с sql server.