УДАЛИТЬ операцию на SQL Сервер очень медленно - PullRequest
1 голос
/ 10 января 2020

У меня есть БД на SQL сервере 2017. Простая таблица с некоторыми внешними ключами и каскадным удалением. Структура очень проста.

Основной tblAS0002 имеет кластерный индекс с идентификатором поля (int). Также все дочерние таблицы tblAS0002_xxx имеют поле внешнего ключа IdAddress, относящееся к полю Id в tblAS0002. Дочерние таблицы для этого образца почти пусты: менее 20000 записей, не более 2 записей на основную запись, в основном все основные записи не имеют связанных записей в дочерних таблицах.

У дочерних таблиц есть индекс на IdAddress (внешний ключ к полю tblAS0002.Id)

Основная таблица (tblAS0002) содержит около 2,5 миллионов записей. Для этого теста я выбираю запись, которая не имеет записей в дочерних таблицах. Когда я сейчас выполняю удаление 1 записи, время выполнения превышает 60 сек.

Оператор, который я выполняю, является прямым DELETE FROM tblAS0002 WHERE Id=2218801

См. План выполнения ниже в опубликованной c ссылке .

Изучив план выполнения, я вижу только одну операцию, занимающую более 1 минуты, и это сканирование индекса первичного ключа tblAS0002. Но почему?

  • DB CC CHECKDB был выполнен.
  • Все индексы были воссозданы.
  • В tblAS0002_History_Links есть 0 записей. (таблица с большим временем выполнения)
  • У записи, которую я удалил для целей тестирования, нет связанной записи ни в одной дочерней таблице! Первичный Id не встречается ни в одной другой таблице как IdAddress (внешний ключ)

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

Здесь Создать скрипт для таблиц (максимально упрощен)

Вставить выполнение план

1 Ответ

2 голосов
/ 11 января 2020

Хороший план исполнения !!! Существует ряд каскадных удалений (которые в свою очередь запускают другие каскадные удаления). каждое удаление -> спул - это еще одно каскадное удаление: удаленные строки помещаются в структуру спул / темп, а спул используется для поиска ссылок на строки из других таблиц.

eg. delete tblAS0002 -> spool[tblAS0002]
delete history{join}spool[tblAS0002] -> spool[history]
delete history_links{join}spool[history]

Просмотр в плане выполнения я вижу только одну операцию, занимающую более 1 минуты, и это сканирование индекса первичного ключа tblAS0002. Но почему?

это операция в нижней части плана.

В tblAS0002 имеется собственная ссылка: tblAS0002.IdParent -> links tblAS0002.Id

Индекс для IdParent отсутствует, удаление одного Id требует сканирования таблицы tblAS0002 по порядку чтобы убедиться, что не существует == assert:! (left semi join), что на удаленный идентификатор не ссылается ни один IdParent.

...