Dlaczego moja baza danych jest nadal fragmentowana po tym, jak wszystko odbudowałem i ponownie zindeksowałem?

41

Mam bazę danych, którą próbowałem defragmentować wszystkie tabele jednocześnie, uruchamiając ten T-SQL:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

A następnie kopiowanie i wklejanie danych wyjściowych do nowego okna zapytania i uruchamianie tego. Nie otrzymałem żadnych błędów, ale nadal mam fragmentację. Próbowałem też uruchomić oba polecenia osobno i nadal mam fragmentację. Uwaga: Zostałem poinformowany, że REORGANIZEnie jest konieczne przez Aarona, i jestem świadomy mogę użyć dynamicznego SQL w celu zautomatyzowania tego.

Uruchomiłem to, aby stwierdzić, że nadal mam fragmentację:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

I mam:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Wiem, że brakuje mi czegoś naprawdę podstawowego, ale nie wiem co.

Justin Dearing
źródło
Jakie masz błędy? Czy jest też powód, dla którego masz to zreorganizować i odbudować to samo?
Shawn Melton
Shawn, przepraszam za brak jednego słowa. Mam żadnych błędów. Co do tego, dlaczego uruchomiłem oba polecenia, zrobiłem to po wypróbowaniu każdego polecenia osobno. Zaktualizowałem swoje pytania.
Justin Dearing

Odpowiedzi:

38

Stoły są małe. Liczba stron w twoich tabelach to:

11, 8, 6, 5, 13, 8, 10

Zajmują łącznie 480 kb. Nie ma dosłownie nic do defragmentacji.

Edycja: To wymaga trochę więcej wyjaśnień.

Nowej tabeli lub indeksowi zwykle przypisuje się pierwsze 8 stron z mieszanego, a nie jednolitego zakresu. Tak więc możliwe jest przydzielenie każdej z pierwszych 8 stron z różnych zakresów mieszanych. Tabela lub indeks zajmujący 8 stron może zatem mieć 8 fragmentów, po 1 na każdym z 8 różnych mieszanych zakresów.

Powszechnie używane skrypty defragmentacyjne (kilka przykładów poniżej) z tego powodu wykluczają małe tabele. IIRC <500 stron znajduje się na jednej lub obu z nich. Przy tych rozmiarach defragmentacja jest bardzo niewielka, a dane dotyczące fragmentacji są potencjalnie zniekształcone przez przydziały o mieszanym zakresie.

Mark Storey-Smith
źródło
Ok, to jest zadowalające, chyba że ktoś inny ma lepszą odpowiedź. Oznaczę twoją jako poprawną.
Justin Dearing
3
+1 Zgadzam się z Markiem. Martw się fragmentacją, gdy faktycznie masz jakieś dane. :-)
Aaron Bertrand
Całkowicie rozumiem, co mówisz. Ale z czystej ciekawości, czy to dlatego, że silnik db po prostu nie może defragmentować tak niewielu stron? To znaczy, musi być ku temu powód.
Thomas Stringer
3
To nie tak, że nie może, ale dlaczego miałoby to przeszkadzać? Może to mieć niewielki lub żaden wpływ na operacje we / wy - zwłaszcza, że ​​tak małe tabele są prawie na pewno w pamięci.
Aaron Bertrand
1
Właśnie. Wydaje się dziwne, to wszystko. Powiedzmy, że piszę aplikację do sprawdzania i raportowania fragmentacji indeksu, musiałbym dodać dodatkową logikę, aby nie tylko przetestować procent fragu, ale także liczbę stron, aby nie było fałszywych alarmów.
Thomas Stringer,
19

Cytat z „ Najlepsze praktyki dotyczące defragmentacji indeksu Microsoft SQL Server 2000 ”:

„Fragmentacja wpływa na operacje wejścia / wyjścia na dysku. Dlatego skup się na większych indeksach, ponieważ ich strony nie są buforowane przez SQL Server. Skorzystaj z liczby stron zgłoszonej przez DBCC SHOWCONTIG, aby dowiedzieć się o wielkości indeksów (każda strona jest 8 KB) Ogólnie rzecz biorąc, nie powinieneś się przejmować poziomem fragmentacji indeksów z mniej niż 1000 stron W testach indeksy zawierające ponad 10 000 stron zrealizowały wzrost wydajności, przy czym największe zyski indeksów przy znacznie większej liczbie stron (większe niż 50 000 stron) ”.

Ten rodzaj odpowiedzi odpowiada na twoje pytanie i wspiera odpowiedzi Marka i Aarona.

Dobre informacje na temat fragmentacji indeksu można znaleźć w następujących artykułach Brenta Ozara:

Ponadto ... ocean świetnych informacji o indeksach w ogóle (także o problemach z fragmentacją) można znaleźć na blogu Kimberly Tripp .

Marian
źródło
12

To nie ma na celu odpowiedzieć na twoje pytanie, ale nigdy nie zmieści się w komentarzu. Możesz zbudować ten skrypt dynamicznie, bez konieczności kopiowania i wklejania danych wyjściowych do innego okna. Biorąc pod uwagę, że nie ma absolutnie żadnego powodu, aby REORGANIZEa następnie REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Aaron Bertrand
źródło
Aaron, dzięki za wskazanie dynamicznego sql, jestem świadomy dynamicznego sql, nie zamierzałem automatyzować rozwiązania, dopóki nie zadziałało. Inni czytający to powinni być jednak świadomi.
Justin Dearing