Wie kann die HEAP-Fragmentierung in SQL Server verringert werden?

10

Ich habe kürzlich herausgefunden, dass eine Heap-Tabelle mehr als 70% fragmentiert ist. Also habe ich beschlossen, eine zu machen

ALTER TABLE dbo.myTable REBUILD

Komisch genug, danach hatte ich 20% Fragmentierung. Seitdem wurde nicht mehr auf diesen Tisch geschrieben. Also habe ich beschlossen, den Umbau noch einmal durchzuführen.

Nach dem 2. Mal hat der Tisch 50% Fragmentierung, also noch mehr! Ich verstehe wirklich nicht, wie das passieren kann ...

Smoking
quelle
Was meinst du mit logischer Fragmentierung? Es ist die Fragmentierung in Bezug auf die Nutzung von Datenseiten. Ich weiß, dass es keine Reihenfolge gibt, aber ungeordnete Daten sind nicht per se fragmentiert. Fragmentierung bedeutet in diesem Fall eine effiziente Nutzung von Datenseiten.
Tuxmania
2
Ich denke wir sollten fragen, wie groß der Tisch ist. In Zeilen und Seiten.
Cody Konior

Antworten:

17

Was bedeutet Fragmentierung in einem Haufen?

Der Fragmentierungswert in Heap, den Sie avg_fragmentation_in_percentdurch Abfragen von sys.dm_db_index_physical_statsDMV aus der Spalte erhalten, gibt dies an

Logische Fragmentierung für Indizes oder Extent-Fragmentierung für Heaps in der Zuordnungseinheit IN_ROW_DATA.

Weiter sagt das gleiche BOL das

Dies ist der Prozentsatz der nicht in der Reihenfolge liegenden Ausmaße auf den Blattseiten eines Haufens. Ein Bereich außerhalb der Reihenfolge ist ein Bereich, bei dem der Bereich, der die aktuelle Seite für einen Heap enthält, physisch nicht der nächste Bereich nach dem Bereich ist, der die vorherige Seite enthält.

Sie sehen also, dass nicht der freie Speicherplatz auf den Heap zugewiesenen Seiten, sondern die unterschiedliche Reihenfolge der Seiten die Fragmentierung verursacht.

Dies kann durch einen kleinen Test nachgewiesen werden. Lassen Sie uns eine Heap-Tabelle erstellen, einige Datensätze einfügen und dann die Fragmentierung überprüfen.

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')

Die Heap-Tabelle wird also mit 50 Datensätzen erstellt. Nachfolgend sehen Sie, wie die Fragmentierung nach der Abfrage DMV sys.dm_db_index_physical stats aussieht

Geben Sie hier die Bildbeschreibung ein

Sie können sehen, dass der avg_fragmentation_in_percentSpaltenwert 33% beträgt. Nun wollen wir sehen, wie die Seiten angeordnet sind. Dies kann mithilfe einer undokumentierten Abfrage erfolgen %%lockres%%. Die Abfrage wäre

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

Und unten sehen Sie, wie die Ausgabe aussieht. Nur relevanten Teil davon anhängen. Die Abfrage ergab 50 Zeilen, da wir 50 Zeilen in unsere Tabelle dbo.HeapTest eingefügt haben.

Geben Sie hier die Bildbeschreibung ein

Es heißt, die erste Seite hat eine ID, 197die nächste Seite hat eine ID. Die 242nachfolgenden Seiten haben eine fortlaufende ID, bis wir die Seiten-ID erreichen, 264da wir danach die Seiten-ID erhalten 280. Dieser Sprung in den Seiten-ID-Nummern verursacht also tatsächlich eine Fragmentierung.

Damit der Heap nicht neu erstellt und der Befehl erneut ausgeführt wird, um die Fragmentierung und die Anordnung der Seiten anzuzeigen. Wir bekommen Fragmentierung wie

Geben Sie hier die Bildbeschreibung ein

Sie können sehen, Fragmentierung ist jetzt 14%.

Lassen Sie uns die zugewiesenen Seitenzahlen sehen

Geben Sie hier die Bildbeschreibung ein

Wir haben nur eine Sprungauflage. Allen Seiten wird die Seiten-ID seriell zugewiesen. Da nur eine Sprungfragmentierung erheblich abnahm.

Ich habe den Heap wieder aufgebaut und jetzt, als ich die Fragmentierung überprüft habe, war er vollständig verschwunden. Und die Zuweisung der Seiten-ID ist wie

Geben Sie hier die Bildbeschreibung ein

Warum die Fragmentierung zunahm

In Bezug auf das, was zu einem Anstieg der Fragmentierung hätte führen können, können wir bestätigen, dass Seiten, die dem Heap zugewiesen wurden, nicht kontinuierlich waren, wie Sie oben gesehen haben, was zu einem Anstieg des Fragmentierungswerts führte, war ein Sprung in die den Seiten zugewiesenen PAGE-IDs.

Am Hinterkopf sollten Sie auch bedenken, dass das Wort Fragmentierung für HEAP keine Bedeutung hat. Wie würden Sie die Fragmentierung für eine Reihe nicht geordneter Seiten definieren?

Wirklich besorgt über Fragmentierung

Wenn Sie wirklich mit einem Szenario konfrontiert sind, in dem die Heap-Tabelle fragmentiert ist und Abfragen verlangsamt, ist es besser, einen Clustered-Index für die Tabelle zu erstellen, als ihn neu zu erstellen. Der Grund dafür ist, dass beim Neuerstellen des Heaps alle zugrunde liegenden Nicht-Clustered-Indizes ebenfalls neu erstellt werden, was dazu führt, dass der Wiederherstellungsprozess viel länger dauert, viele Ressourcen verbraucht und das Transaktionsprotokoll aufgebläht wird. Auf einem Produktionssystem würde man immer versuchen, dies zu vermeiden. Paulus hat dies in seiner Mythos-Sektion über Haufen behandelt .

PS: Bitte verwenden Sie keinen undokumentierten Befehl auf dem Produktionssystem. Dies war nur zur Demonstration.

Shanky
quelle
Vielen Dank für Ihre detaillierte Analyse. Ich stehe vor großen Heap-Tabellen, weil einige Data Vault-Enthusiasten der Meinung sind, dass dies viel besser ist als die Verwendung von Clustered-Indizes, aber dann verwenden sie viele Überprüfungsbeschränkungen und nicht-Clustered-Indizes für diese Heaps, sodass ich den Nutzen von Heaps in dieser Situation nicht wirklich sehe. Da ich jedoch nur der dumme Entwickler bin, muss ich mich damit befassen.
Nochmals vielen
Wie führe ich select index_type_desc, avg_fragmentation_in_percent, fragment_count, avg_page_space_used_in_percent, record_count aus sys.dm_db_index_physical_stats (db_id (), object_id ('dbo.HeapTest', 'U'), ' ein Tisch ? Es gibt für mich alle Indizes aller Tabellen zurück, auch wenn ich meinen Tabellennamen in 'object_id' korrekt angegeben habe
Mickael
@Mickael Ich habe die Funktion db_id () verwendet, die die aktuelle Datenbank übernehmen würde, und ich habe speziell den Objektnamen angegeben, damit diese immer in die aktuelle Datenbank schauen Heaptestund das Ergebnis suchen und angeben . Ich bin sicher, Sie haben vielleicht etwas verpasst. Stellen Sie einfach sicher, dass die Kompatibilitätsstufe nicht 80 ist. In diesem Fall funktioniert die Funktion db_id nicht
Shanky,
@Shanky, warum empfehlen Sie nicht, die undokumentierte Abfrage %% lockres %% in der Produktion zu verwenden? Könnten Sie es im Detail erklären?
Ralph
@ user1624552 Nur weil es nicht dokumentiert ist, bedeutet dies, dass MS auch die Dokumentation darüber nicht aktualisiert. Was sind seine Nachwirkungen, wie es funktioniert, ist nirgendwo dokumentiert, deshalb wird es gefragt. Beispiel: Es gibt den Befehl fn_dump_dblog (), der einen versteckten Scheduler erstellt , und das ist nicht gut. Dieser Befehl wird ebenfalls nicht unterstützt. Sie können es verwenden, aber das Risiko liegt bei Ihnen.
Shanky