Jak obniżyć fragmentację HEAP w SQL Server?

10

Niedawno dowiedziałem się, że jedna tabela sterty ma fragmentację powyżej 70%. Więc postanowiłem zrobić

ALTER TABLE dbo.myTable REBUILD

Zabawne, potem miałem 20% fragmentacji. Odtąd nie było na tym stole żadnego zapisu. Więc postanowiłem zrobić przebudowę jeszcze raz.

Po 2 razach stół rozdrabnia 50% fragmentacji, więc jeszcze więcej! Naprawdę nie rozumiem, jak to się może stać ...

tuxmania
źródło
Co masz na myśli mówiąc logiczną fragmentację. Jest to fragmentacja pod względem wykorzystania stron danych. Wiem, że nie ma porządku, ale nieuporządkowane dane nie są fragmentowane per se. Fragmentacja w tym przypadku oznacza efektywne wykorzystanie stron danych.
tuxmania,
2
Chyba powinniśmy zapytać, jak duży jest ten stół? W rzędach i na stronach.
Cody Konior

Odpowiedzi:

17

Co oznacza fragmentacja w kupie

Stwierdzono, że wartość fragmentacji w Sterty, którą otrzymujesz z kolumny avg_fragmentation_in_percentpoprzez zapytanie sys.dm_db_index_physical_statsDMV

Fragmentacja logiczna dla indeksów lub fragmentacja zasięgu dla hałd w jednostce alokacji IN_ROW_DATA.

Dalej ten sam BOL tak mówi

Jest to procent zakresu poza kolejnością na stronach liści sterty. Zasięg poza kolejnością to taki, dla którego zasięg zawierający bieżącą stronę sterty nie jest fizycznie następnym zasięgiem po zakresie zawierającym poprzednią stronę.

Widzisz więc, że fragmentacja nie powoduje wolnego miejsca na stronach przypisanych do Sterty, ale zmienną sekwencję stron .

Można to wykazać za pomocą małego testu. Stwórzmy Stertę Stert i wstawmy do niej niektóre rekordy, a następnie sprawdź fragmentację.

create table dbo.HeapTest
(
Id INT not NULL Default (1),
Col1   char(5000) Not null Default ('Heaps Are Cool')
)

SET NOCOUNT ON

Insert into dbo.Heaptest default values
go 50

select index_type_desc,avg_fragmentation_in_percent,fragment_count,
avg_page_space_used_in_percent,record_count
from sys.dm_db_index_physical_stats(db_id(),object_id('dbo.HeapTest','U'),0,default,'detailed')

Tak więc tworzona jest tabela sterty z 50 rekordami. Poniżej wygląda fragmentacja po zapytaniu statystyki DMV sys.dm_db_index_physical

wprowadź opis zdjęcia tutaj

Można zobaczyć avg_fragmentation_in_percentwartość kolumny wynosi 33%. Zobaczmy teraz, jak są ułożone strony. Można to zrobić za pomocą nieudokumentowanego zapytania %%lockres%%. Zapytanie byłoby

SELECT  %%lockres%%, * FROM dbo.HeapTest;

A poniżej wygląda wyjście. Dołączanie tylko odpowiedniej części. Kwerenda wygenerowała 50 wierszy, ponieważ wstawiliśmy 50 wierszy do naszej tabeli dbo.HeapTest.

wprowadź opis zdjęcia tutaj

Mówi się, że pierwsza strona ma identyfikator, 197następna strona ma identyfikator, 242kolejne strony mają ciągły identyfikator, dopóki nie osiągniemy identyfikatora strony, 264ponieważ potem otrzymamy identyfikator strony 280. Tak więc skok numerów identyfikacyjnych stron powoduje fragmentację.

Teraz nie odbuduj sterty i nie uruchom ponownie polecenia, aby zobaczyć fragmentację i sposób ułożenia stron. Otrzymujemy fragmentację jak

wprowadź opis zdjęcia tutaj

Widać, że fragmentacja jest teraz 14%.

Zobaczmy przydzielone numery stron

wprowadź opis zdjęcia tutaj

Mamy tylko jeden skok, wszystkie strony mają przypisany identyfikator strony. Ponieważ tylko jedna fragmentacja skoku znacznie się zmniejszyła.

Ponownie odbudowuję Stertę i teraz, gdy sprawdziłem fragmentację, całkowicie zniknęła. Przydział identyfikatora strony jest podobny

wprowadź opis zdjęcia tutaj

Dlaczego zwiększona fragmentacja?

Teraz, jeśli chodzi o to, co mogło spowodować wzrost fragmentacji, możemy potwierdzić, że kiedy strony były przydzielane do stosu, nie byłyby one ciągłe, jak widać powyżej, co spowodowało wzrost wartości fragmentacji, to skok w przypisaniu stron ID PAGE.

Z tyłu głowy należy również pamiętać, że fragmentacja słowa dla HEAP nie ma żadnego znaczenia, jak zdefiniowałbyś fragmentację dla grupy niezamówionych stron.

Naprawdę martwiłem się o fragmentację

Jeśli naprawdę masz do czynienia ze scenariuszem, w którym tabela sterty jest pofragmentowana i spowalnia zapytania, lepiej byłoby utworzyć indeks klastrowany w tabeli niż odbudować go. Powodem jest to, że podczas przebudowywania sterty wszystkie bazowe indeksy nieklastrowane są również przebudowywane, co powoduje, że proces przebudowywania zajmuje znacznie więcej czasu, zużywa dużo zasobów i powoduje wzdęcie dziennika transakcji. W systemie produkcyjnym zawsze starano się tego uniknąć. Paul opisał to w swojej sekcji mitów o kupie .

PS: Nie używaj nieudokumentowanej komendy w systemie produkcyjnym. To było tylko na pokaz.

Shanky
źródło
Dziękujemy za szczegółową analizę. Mam do czynienia z dużymi tabelami sterty, ponieważ niektórzy entuzjaści przechowalni danych uważają, że jest to znacznie lepsze niż używanie indeksów klastrowych, ale wtedy używają wielu ograniczeń sprawdzania i indeksów nieklastrowych na tych hałdach, więc w tej sytuacji nie widzę korzyści ze stosów. Ponieważ jednak jestem tylko głupim programistą, muszę sobie z tym poradzić.
Jeszcze
W jaki sposób uruchamiasz select index_type_desc, avg_fragmentation_in_percent, fragment_count, avg_page_space_used_in_percent, record_count from sys.dm_db_index_physical_stats (db_id (), object_id ('dbo.HeapTest', 'U') szczegółowy, tylko domyślny, zwracany wynik 0, domyślny jeden stół ? zwraca mi wszystkie indeksy we wszystkich tabelach, nawet jeśli poprawnie podam nazwę tabeli w 'object_id'
Mickael
@Mickael Użyłem funkcji db_id (), która pobierałaby bieżącą bazę danych, a ja konkretnie podałem nazwę obiektu, aby zawsze sprawdzał bieżącą bazę danych i szukał Heaptesti dawał wynik. Jestem pewien, że coś przegapiłeś. Tylko upewnij się, że poziom kompatybilności nie jest 80 w tym przypadku funkcja db_id źle działa
Shanky
@Shanky, dlaczego nie zalecamy używania nieudokumentowanego zapytania %% lockres %% w produkcji? Czy mógłbyś to szczegółowo wyjaśnić?
Ralph
@ user1624552 Po prostu dlatego, że jest nieudokumentowany, oznacza to, że MS również nie aktualizuje dokumentacji na jego temat. Jakie są jego następstwa, jak to działa, nie jest nigdzie udokumentowane, dlatego jest o to proszony. Na przykład istnieje polecenie fn_dump_dblog (), które tworzy ukryty harmonogram i to nie jest dobre. To polecenie również nie jest obsługiwane. Możesz z niego korzystać, ale ryzyko spoczywa na Tobie.
Shanky