SQL Server „pusta tabela” jest powolna po usunięciu wszystkich (12 milionów) rekordów?

27

Mam instancję SQL Server 2008 z około 150 kolumnami. Wcześniej wypełniłem tę tabelę około 12 milionami wpisów, ale odtąd wyczyściłem tabelę w ramach przygotowań do nowego zestawu danych.

Jednak polecenia, które prowadził kiedyś od razu w pustym stole, takie jak count(*)i select top 1000na SQL Management Studioteraz podjąć eony uruchomić.

SELECT COUNT(*) FROM TABLE_NAME 

zwrócenie 0 zajęło ponad 11 minut, a SELECT TOP 1000powrót pustego stolika zajęło prawie 10 minut.

Zauważyłem również, że wolne miejsce na moim dysku twardym dosłownie zniknęło (z około 100G do 20G). Jedyne, co się wydarzyło, to jedno zapytanie, które uruchomiłem:

DELETE FROM TABLE_NAME

Co się dzieje na świecie?!?


źródło
5
Z jakiego modelu odzyskiwania korzysta baza danych? Jeśli jest „Pełny”, instancja SQL przechowuje zapis wszystkich tych usunięć, które mogą być miejscem, w którym poszło wolne miejsce. Jeśli wymagane jest pełne odzyskiwanie, zalecamy użycie TRUNCATE TABLEzamiast DELETE FROM.
Tullo_x86
2
150 kolumn? Ten stół może być przepełniony - większość krotek powinna być znacznie mniejsza. Nie można jednak powiedzieć bez pełnego kontekstu.
Clockwork-Muse

Odpowiedzi:

42

Powiedziano ci już, dlaczego TRUNCATEbyłby o wiele szybszy / lepszy / seksowniejszy DELETE, ale wciąż pozostaje pytanie:

Dlaczego SELECTpo DELETE zakończeniu działa wolniej ?

To dlatego, DELETEże tylko widmo wierszy. Tabela jest tak duża, jak wtedy, gdy miała 12 mln wierszy, nawet jeśli nie ma. Aby zliczyć rzędy (0), zajmuje tyle samo czasu, ile potrzeba, aby zliczyć 12 milionów wierszy. Z czasem proces czyszczenia duchów usunie te duchowe rekordy i cofnie przydział stron, które zawierały tylko duchy, a twoje SELECT przyspieszy. Ale teraz, jeśli zameldujesz się Skipped Ghosted Records/secw perfmon, prawdopodobnie gwałtownie rośnie SELECT COUNT(*). Można również przyspieszyć rzeczy poprzez przebudowę tabeli: ALTER TABLE ... REBUILD.

TRUNCATE zająłby się także tym problemem, ponieważ nie pozostawia po sobie żadnych duchów.

Zobacz także Inside the Storage Engine: Dogłębne czyszczenie duchów .

Remus Rusanu
źródło
13

DELETEinstrukcje usuwają wiersze z tabeli pojedynczo, rejestrując każdy wiersz w transaction log, a także zachowując log sequence number (LSN)informacje. Ponieważ wspomniano, że w tabeli znajdują się ogromne dane (12 milionów rekordów), po usunięciu którego na dysku twardym brakuje miejsca, sprawdź rozmiar pliku dziennika bazy danych. Najprawdopodobniej urósłoby.

Lepszym sposobem byłoby:

TRUNCATE TABLE_NAME

źródło
2
+1, dokładnie taka sama prawda dla Oracle DB. Jeśli użyjesz instrukcji, które powodują zapisywanie rekordów, z czasem spowolni bazę danych.
Petro Semeniuk
@ PetroSemeniuk Z tego, co pamiętam na Oracle, usuń pozostawia znak wysokiej wody w spokoju, obcinanie zresetuje znak wysokiej wody. Wierzę, że wszelkie operacje wymagające pełnego skanowania będą skanować bloki, aż do znaku wysokiej wody. W związku z tym usunięcie może pomóc indeksowanym operacjom, ale nie skanom. TRUNCATE było właściwą operacją.
Glenn
3

(To był pierwotnie komentarz do odpowiedzi @ DaveE, ale umieściłem go we własnej odpowiedzi, ponieważ stał się długi)

TRUNCATE jest zarejestrowaną operacją. Musi być inaczej, ponieważ nie jest zgodny z ACID. Jednak różnice między TRUNCATEi DELETE:

  • Wykorzystanie miejsca do rejestrowania: TRUNCATEzwalnia tylko strony / zakresy *, podczas gdy DELETErejestruje pojedyncze wiersze.
  • Zablokuj użycie: TRUNCATEgeneralnie używa mniej blokad, ponieważ wymaga blokady tabeli i blokad strony, w przeciwieństwie do DELETEblokad wierszy **.
  • IDENTITYsekwencje: TRUNCATEresetuje sekwencję tożsamości w tabeli, jeśli jest obecna.

(* Zakres = 8 stron. TRUNCATELoguje / usuwa zakresy, jeśli wszystkie są z tej samej tabeli, w przeciwnym razie loguje / usuwa strony z zakresu mieszanego.

** Jednym z efektów ubocznych jest to, że DELETE FROM TABLEpotencjalnie można pozostawić puste strony przydzielone do tabeli, w zależności od tego, czy operacja może uzyskać wyłączną blokadę tabeli, czy nie.)

Tak więc (wracając do pierwotnego pytania), TRUNCATE TABLEjest zdecydowanie lepszy niż DELETE FROM TABLEwtedy, gdy opróżniasz tabelę, ale chcesz zachować strukturę (NB: TRUNCATEnie można jej używać w tabeli, do której odwołuje się klucz obcy z innej tabeli).

Jak zauważono w komentarzu @ Tullo, sprawdź również model odzyskiwania bazy danych - jeśli jest pełny, albo zacznij robić kopie zapasowe dziennika, albo zmień model odzyskiwania na prosty. Po wykonaniu którejkolwiek z tych czynności prawdopodobnie będziesz chciał zmniejszyć plik dziennika jako operację jednorazową (Uwaga: tylko plik dziennika ) w celu odzyskania całego wolnego miejsca.

Na koniec jeszcze jedna rzecz, o której należy pamiętać - statystyki tabel. uruchom UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE`, aby optymalizator zapytań nie był wyzwalany przez stare statystyki.

Simon Righarts
źródło
2

(UWAGA: nie jestem DBA) DELETE jest zarejestrowaną operacją i nie zwalnia zajętego miejsca. Prawdopodobnie masz duży dziennik transakcji zajmujący miejsce i skanowanie tabel uruchomione na „pustym” obszarze tabel. Myślę, że musisz wyczyścić dziennik transakcji i zmniejszyć bazę danych. Ten artykuł StackOverflow powinien zacząć.

I użyj TRUNCATE TABLE, jeśli chcesz to zrobić w przyszłości.

EDYCJA: Moje stwierdzenie o braku rejestrowania TRUNCATE było błędne. oddalony.

DaveE
źródło