"Пуста таблиця" SQL Server повільна після видалення всіх (12 мільйонів) записів?


27

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

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

SELECT COUNT(*) FROM TABLE_NAME 

щоб повернути 0, SELECT TOP 1000пішло 11 хвилин, і повернути порожній стіл потрібно майже 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) потрібно стільки ж часу, скільки потрібно для підрахунку 12М рядків. З часом процес очищення привидів зібрає сміття з цих примарних записів і розмістить сторінки, що містять лише привидів, і ваші ВИБОРИ прискоряться. Але зараз, якщо ви зареєструєтеся Skipped Ghosted Records/secв парфмоні, ймовірно, стрімко зростає протягом року SELECT COUNT(*). Крім того, можна прискорити процес , шляхом відновлення таблиці: ALTER TABLE ... REBUILD.

TRUNCATE також вирішив би цю проблему, оскільки вона не залишає привидів.

Дивіться також всередині двигуна зберігання: очищення привидів в глибину .


13

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

кращим способом було б:

TRUNCATE TABLE_NAME

2
+1, точно так само і для Oracle DB. Якщо ви використовуєте оператори, які викликають записи в журнал, це сповільнить базу даних з часом.
Петро Семенюк

@PetroSemeniuk З того, що я згадую в Oracle, видалення залишків високого водного знаку в спокої, усікання скине знак високої води. Я вірю, що будь-які операції, які потребують повного сканування, скануватимуть блоки до появи знаку високої води. Отже, видалення може допомогти індексованим операціям, але не сканувати. TRUNCATE була правильною операцією.
Гленн

3

(Спочатку це був коментар до відповіді @ DaveE, але я вклав це у свою відповідь, тому що він отримав тривалий час)

TRUNCATE - це зареєстрована операція. Це повинно бути інакше, що це не сумісне з кислотами. Однак різниці між 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

(ПРИМІТКА: Я не DBA) DELETE - це зареєстрована операція, і вона не звільняє використаний простір. Напевно, у вас великий журнал транзакцій, який займає простір та сканування таблиць, які працюють на «порожньому» просторі таблиці. Я думаю, вам потрібно очистити журнал транзакцій і зменшити вашу базу даних. Ця стаття StackOverflow має розпочати роботу.

І використовуйте TRUNCATE TABLE, коли ви хочете зробити це в майбутньому.

РЕДАКТУВАННЯ. У моїй заяві про те, що TRUNCATE не реєструється, було помилково. вилучено.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.