Warum belegen meine Nonclustered-Indizes mehr Speicherplatz, wenn ich Zeilen lösche?

22

Ich habe eine große Tabelle mit 7,5 Milliarden Zeilen und 5 Indizes. Wenn ich ungefähr 10 Millionen Zeilen lösche, stelle ich fest, dass die nicht gruppierten Indizes die Anzahl der Seiten zu erhöhen scheinen, auf denen sie gespeichert sind.

Ich habe eine Abfrage gegen geschrieben dm_db_partition_stats, um den Unterschied (vorher - nachher) in Seiten zu melden:

dm_db_partition_stats Deltas

Index 1 ist der Clustered-Index, Index 2 ist der Primärschlüssel. Die anderen sind nicht gruppiert und nicht eindeutig.

Warum nehmen die Seiten in diesen nicht gruppierten Indizes zu?
Ich erwartete, dass die Zahlen im schlimmsten Fall gleich bleiben würden.
Ich sehe Leistungsindikatoren, die während des Löschens einen Anstieg der Seitenteile melden.

Muss der Geisterdatensatz beim Löschen auf eine andere Seite verschoben werden? Hat dies mit "Uniqueifiers" zu tun?

Wir sind gerade dabei, RCSI einzuführen, aber im Moment ist RCSI deaktiviert.

Es ist ein primärer Knoten in einer Verfügbarkeitsgruppe. Ich weiß, dass der Schnappschuss irgendwie für Secondaries verwendet wird. Ich wäre überrascht, wenn das relevant wäre. Ich habe vor, mich damit zu beschäftigen (siehe dbcc-Seitenausgabe), um mehr zu erfahren. Wir hoffen, dass jemand etwas Ähnliches gesehen hat.

Michael J Swart
quelle
Nur eine Frage: Führen Sie ein REORGANIZE für einen der gewachsenen Indizes durch. Was passiert? Wie viele Seiten werden entfernt? Und wenn Sie vor dem Löschen neu organisieren, was passiert dann? Ich denke hauptsächlich, dass die internen Mechanismen es in einigen Fällen einfacher finden, eine ganze neue Seite zuzuweisen und zusammenzuführen, aber die leeren Seiten nicht bereinigen. Ich weiß, dass REORGANIZE sogar auf relativ unfragmentierten, aber größeren Indizes erhebliche Seitenmengen ablegt.
Vergil
Gute Frage @LaughingVergil Wenn ich die Antwort habe, komme ich zurück, um es zu melden. (Aber es kann eine Weile dauern).
Michael J Swart
In unserem Fall war dieser Anstieg ein vorübergehendes Phänomen. Mit genügend Geduld erledigte die Ghost-Bereinigung schließlich ihre Arbeit und die Größe der Indizes nahm ab.
Michael J Swart

Antworten:

28

Ein mögliches Szenario, das mich sehr amüsiert:

  • Die Zeilen wurden ursprünglich geschrieben, als in der Datenbank RCSI (Read Committed Snapshot), SI (Snapshot Isolation) oder Verfügbarkeitsgruppen (Availability Groups, AGs) nicht aktiviert waren
  • RCSI oder SI wurde aktiviert oder die Datenbank wurde einer Verfügbarkeitsgruppe hinzugefügt
  • Während der Löschvorgänge wurde den gelöschten Zeilen ein 14-Byte-Zeitstempel hinzugefügt, um RCSI / SI / AG-Lesevorgänge zu unterstützen

Da dieser Server ein Primärserver in einer AG ist, ist er genauso betroffen wie die Sekundärserver. Die Versionsinformationen werden auf der Primärseite hinzugefügt - die Datenseiten sind sowohl auf der Primärseite als auch auf der Sekundärseite identisch. Die Secondaries nutzen den Versionsspeicher, um ihre Lesevorgänge durchzuführen, während die Zeilen von der AG aktualisiert werden. Die Secondaries schreiben jedoch keine eigenen Versionen des Zeitstempels auf die Seite. Sie erben nur die Versionen von der Arbeit des Primärs.

Um das Wachstum zu demonstrieren, habe ich den Stack Overflow-Datenbankexport (für den RCSI nicht aktiviert ist) verwendet und eine Reihe von Indizes für die Posts-Tabelle erstellt. Ich habe die Indexgrößen mit sp_BlitzIndex @Mode = 2 überprüft (in eine Tabelle kopieren / einfügen und ein wenig aufgeräumt, um die Informationsdichte zu maximieren):

sp_BlitzIndex vorher

Ich habe dann ungefähr die Hälfte der Zeilen gelöscht:

BEGIN TRAN;
DELETE dbo.Posts WHERE Id % 2 = 0;
GO

Amüsanterweise wuchs die Datendatei während der Löschvorgänge, um auch die Zeitstempel aufzunehmen! Der SSMS-Datenträgernutzungsbericht zeigt die Wachstumsereignisse - hier ist nur die Oberseite, um zu veranschaulichen:

Wachstumsereignisse

(Ich muss eine Demo lieben, bei der Löschvorgänge die Datenbank vergrößern.) Während der Löschvorgang ausgeführt wurde, habe ich sp_BlitzIndex erneut ausgeführt. Beachten Sie, dass der Clustered-Index weniger Zeilen enthält, seine Größe jedoch bereits um ca. 1,5 GB zugenommen hat. Die nicht gruppierten Indizes auf AcceptedAnswerId sind dramatisch gewachsen - es handelt sich um Indizes mit einem kleinen Wert, der größtenteils null ist, sodass sich ihre Indexgröße fast verdoppelt hat!

sp_BlitzIndex beim Löschen

Ich muss nicht warten, bis der Löschvorgang abgeschlossen ist, um dies zu beweisen, also werde ich die Demo dort stoppen. Das Wichtigste dabei ist: Wenn Sie große Löschvorgänge in einer Tabelle ausführen, die implementiert wurde, bevor RCSI, SI oder AGs aktiviert wurden, können die Indizes (einschließlich der Clustered-Indizes) tatsächlich erweitert werden, um den Zeitstempel des Versionsspeichers hinzuzufügen.

Brent Ozar
quelle
3
Das ist die Erklärung. Es stellt sich heraus, dass andere Umstände dazu führen können, dass 14 Versionsbytes fehlen. In meinen Tests sieht es so aus, als würde die Offline-Neuerstellung eines Indexes die Zeilen ohne die Versionsbytes neu erstellen.
Michael J Swart