Warum ist meine Datenbank immer noch fragmentiert, nachdem ich alles neu erstellt und indiziert habe?


40

Ich habe eine Datenbank, die ich versucht habe, alle Tabellen auf einmal zu defragmentieren, indem ich diese T-SQL ausführe:

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

Kopieren und Einfügen der Ausgabe in ein neues Abfragefenster und Ausführen dieses Fensters. Ich habe keine Fehler, aber ich habe immer noch Fragmentierung. Ich habe versucht, beide Befehle auch separat auszuführen und habe immer noch Fragmentierung. Hinweis: Mir wurde bewusst, dass REORGANIZEAaron dies nicht benötigt, und ich bin mir bewusst, dass ich dynamisches SQL verwenden könnte, um dies zu automatisieren.

Ich habe dies ausgeführt, um festzustellen, dass ich noch Fragmentierung habe:

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

Und ich habe:

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

Ich weiß, dass mir etwas Grundlegendes fehlt, aber ich weiß nicht was.


Welche Fehler haben Sie bekommen? Gibt es auch einen Grund, warum Sie das gleiche neu organisieren und neu erstellen lassen?
Shawn Melton

Shawn, ich entschuldige mich für das Fehlen eines Wortes. Ich habe keine Fehler bekommen. Warum ich beide Befehle ausgeführt habe, habe ich getan, nachdem ich jeden Befehl einzeln ausprobiert hatte. Ich habe meine Fragen aktualisiert.
Justin Dearing

Antworten:


38

Die Tische sind winzig. Die Seitenzahlen in Ihren Tabellen sind:

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

Sie belegen insgesamt 480kb. Es gibt buchstäblich nichts zu defragmentieren.

Edit: Dies bedarf einer etwas ausführlicheren Erklärung.

Einer neuen Tabelle oder einem neuen Index werden normalerweise die ersten 8 Seiten in einem gemischten und nicht einheitlichen Umfang zugewiesen. So ist es möglich, dass jede der ersten 8 Seiten aus verschiedenen gemischten Bereichen zugewiesen wird. Eine Tabelle oder ein Index, die bzw. der 8 Seiten belegt, kann daher 8 Fragmente enthalten, von denen sich jeweils 1 in 8 verschiedenen gemischten Bereichen befindet.

Die am häufigsten verwendeten Defragmentierungsskripte (einige Beispiele unten) schließen kleine Tabellen aus diesem Grund aus. IIRC, <500 Seiten befinden sich in einer oder beiden. Bei diesen Größen bietet die Defragmentierung nur einen geringen Vorteil, und die Fragmentierungszahlen werden möglicherweise durch die gemischten Extent-Zuordnungen verzerrt.


Ok, das ist zufriedenstellend, es sei denn, jemand anderes hat eine bessere Antwort. Ich werde deine als richtig markieren.
Justin Dearing

3
+1 Mit Mark einverstanden. Sorgen Sie sich um die Fragmentierung, wenn Sie tatsächlich Daten haben. :-)
Aaron Bertrand

Ich verstehe vollkommen, was du sagst. Aber nur aus reiner Neugier, kann die Datenbank-Engine nicht so wenige Seiten defragmentieren? Ich meine, es muss einen Grund dafür geben.
Thomas Stringer

3
Es ist nicht so, dass es nicht kann, aber warum sollte es stören? Dies wird sich kaum oder gar nicht auf die E / A auswirken - zumal Tabellen dieser Größe sowieso fast garantiert im Speicher sind.
Aaron Bertrand

1
Gerade. Scheint seltsam, das ist alles. Angenommen, ich schreibe eine Anwendung zum Überprüfen und Melden der Indexfragmentierung. Dann müsste ich zusätzliche Logik hinzufügen, um nicht nur den Prozentsatz der Fragmente, sondern auch die Anzahl der Seiten zu testen, damit keine Fehlalarme auftreten.
Thomas Stringer

18

Zitat aus " Best Practices für die Microsoft SQL Server 2000-Indexdefragmentierung ":

"Die Fragmentierung wirkt sich auf die Datenträger - E / A aus. Konzentrieren Sie sich daher auf die größeren Indizes, da deren Seiten mit geringerer Wahrscheinlichkeit von SQL Server zwischengespeichert werden. Verwenden Sie die von DBCC SHOWCONTIG gemeldete Seitenzahl, um eine Vorstellung von der Größe der Indizes zu erhalten (jede Seite hat eine bestimmte Größe) 8 KB) Im Allgemeinen sollten Sie sich nicht mit der Fragmentierung von Indizes mit weniger als 1.000 Seiten befassen. In den Tests erzielten Indizes mit mehr als 10.000 Seiten Leistungszuwächse, wobei die größten Zuwächse bei Indizes mit erheblich mehr Seiten (mehr) zu verzeichnen waren als 50.000 Seiten) . "

Diese Art beantwortet also Ihre Frage und unterstützt Marks und Aarons Antworten.

Gute Informationen zur Indexfragmentierung finden Sie in folgenden Artikeln von Brent Ozar:

Auf Kimberly Tripps Blog finden Sie eine Fülle großartiger Informationen über Indizes im Allgemeinen (auch über Fragmentierungsprobleme) .


11

Dies ist nicht dazu gedacht, Ihre Frage zu beantworten, aber es wird niemals in einen Kommentar passen. Sie können dieses Skript dynamisch erstellen, ohne die Ausgabe in ein anderes Fenster kopieren und einfügen zu müssen. In Anbetracht dessen, dass es absolut keinen Grund gibt, REORGANIZEund dann 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, danke für den Hinweis auf das dynamische SQL. Ich kenne das dynamische SQL sehr gut. Ich wollte die Lösung erst dann automatisieren, wenn es funktioniert hat. Andere, die dies lesen, sollten sich jedoch dessen bewusst sein.
Justin Dearing
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.