SQL Server «пустая таблица» работает медленно после удаления всех (12 миллионов) записей?

27

У меня есть экземпляр SQL Server 2008 с примерно 150 столбцами. Ранее я заполнил эту таблицу приблизительно 12 миллионами записей, но с тех пор очистил таблицу при подготовке к новому набору данных.

Тем не менее, команды , которые когда - то бегала мгновенно на пустой столик , такой как count(*)и select top 1000в SQL Management Studioнастоящее берут эоны бежать.

SELECT COUNT(*) FROM TABLE_NAME 

потребовалось 11 минут, чтобы вернуть 0, и SELECT TOP 1000почти 10 минут, чтобы вернуть пустой стол.

Я также заметил, что свободное место на моем жестком диске буквально исчезло (примерно с 100G до 20G). Единственное, что произошло между ними, был один запрос, который я запустил:

DELETE FROM TABLE_NAME

Что происходит в мире?!?


источник
5
Какую модель восстановления использует ваша база данных? Если он «Полный», ваш экземпляр SQL будет хранить записи обо всех этих удалениях, которые могут находиться там, где было свободное место. Если требуется полное восстановление, я рекомендую использовать TRUNCATE TABLEвместо DELETE FROM.
Tullo_x86
2
150 столбцов? Эта таблица может быть переполнена - большинство кортежей должно быть намного меньше. Однако невозможно сказать без полного контекста.
Заводная муза

Ответы:

42

Вам уже говорили о том, почему TRUNCATEбыло бы намного быстрее / лучше / сексуальнее DELETE, но все еще остается вопрос:

Почему SELECTмедленнее после DELETE завершения ?

Это потому, DELETEчто только призраки строк. Таблица такая же большая, как и тогда, когда в ней было 12 миллионов строк, хотя в ней нет ни одной. Для подсчета строк (0) требуется столько же времени, сколько и для подсчета 12M строк. Со временем процесс очистки призраков соберет эти записи и освободит страницы, которые содержат только призраков, и ваш SELECTs ускорится. Но прямо сейчас, если вы зарегистрируетесь Skipped Ghosted Records/secв perfmon, вероятно, стремительный рост во время SELECT COUNT(*). Кроме того, можно ускорить процесс , путем восстановления таблицы: ALTER TABLE ... REBUILD.

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

См. Также « Внутри механизма хранения: тщательная очистка призрака» .

Ремус Русану
источник
13

DELETEоператоры удаляют строки из таблицы по одной, регистрируя каждую строку в transaction log, а также сохраняя log sequence number (LSN)информацию. Поскольку вы упомянули, что в вашей таблице хранятся огромные данные (12 миллионов записей), после удаления из которых на жестком диске не осталось места, проверьте размер файла журнала базы данных. Скорее всего, он вырос.

Лучшим способом было бы:

TRUNCATE TABLE_NAME

источник
2
+1, точно так же верно для БД Oracle. Если вы используете операторы, которые заставляют записи регистрироваться, это замедлит работу базы данных с течением времени.
Петр Семенюк
@PetroSemeniuk Из того, что я вспоминаю в Oracle, удаление оставляет только марку highwater, усечение сбрасывает метку highwater. Я полагаю, что любые операции, которые требуют полного сканирования, будут сканировать блоки до максимальной отметки. Следовательно, удаление может помочь индексированным операциям, но не сканированию. TRUNCATE была правильной операцией.
Гленн
3

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

TRUNCATE это вошедший операция. В противном случае он не совместим с ACID. Тем не менее, различия между TRUNCATEи DELETE:

  • Использование пространства журнала: TRUNCATEтолько журналы страниц / экстентов * освобождаются, тогда как DELETEрегистрируются отдельные строки.
  • Использование блокировок: TRUNCATEобычно используется меньше блокировок, так как он использует блокировку таблицы и блокировки страниц, в отличие от DELETEблокировок строк **.
  • IDENTITYпоследовательности: TRUNCATEсбрасывает идентичную последовательность в таблице, если она присутствует.

(* Экстент = 8 страниц. TRUNCATEБудет регистрировать / удалять экстенты, если они все из этой таблицы, в противном случае он будет регистрировать / удалять страницы из смешанных экстентов.

** Одним из побочных эффектов этого является то, что DELETE FROM TABLEпотенциально можно оставить пустые страницы, выделенные для таблицы, в зависимости от того, может ли операция получить исключительную блокировку таблицы или нет.

Итак (вернемся к исходному вопросу), TRUNCATE TABLEбезусловно, лучше, чем DELETE FROM TABLEесли вы очищаете таблицу, но хотите сохранить структуру (примечание: TRUNCATEнельзя использовать для таблицы, на которую ссылается внешний ключ из другой таблицы).

Как отмечается в комментарии @ Tullo, также проверьте модель восстановления базы данных - если она заполнена, то вам нужно либо начать делать резервные копии журналов, либо изменить модель восстановления на простую. После того, как вы выполнили одно из этих действий, вы, вероятно, захотите сжать файл журнала как разовую операцию (NB: только файл журнала ), чтобы освободить все это свободное пространство.

Наконец, еще одна вещь, о которой нужно знать - таблица статистики. запустите UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE`, чтобы оптимизатор запросов не сработал из-за старой статистики.

Саймон Ригартс
источник
2

(ПРИМЕЧАНИЕ: я не администратор базы данных). DELETE - это зарегистрированная операция, которая не освобождает используемое пространство. Возможно, у вас большой журнал транзакций, занимающий пространство, и сканирование таблиц выполняется в «пустом» табличном пространстве. Я предполагаю, что вам нужно очистить журнал транзакций и сжать базу данных. Эта статья StackOverflow должна помочь вам начать.

И используйте TRUNCATE TABLE, если вы хотите сделать это в будущем.

РЕДАКТИРОВАТЬ: мое утверждение о том, что TRUNCATE не был зарегистрирован, был ошибочным. удален.

DaveE
источник