Welche Auswirkung hat die Reduzierung der Größe einer varchar-Spalte auf die Datenbankdatei?

15

Wir haben eine Reihe von Tabellen in unserer Datenbank, die VARCHAR(MAX)Spalten enthalten, in denen ein VARCHAR(500)(oder etwas viel kleineres als das Maximum) ausreicht. Natürlich möchte ich diese aufräumen und die Größen auf ein vernünftigeres Maß reduzieren. Das "Wie" dazu verstehe ich: Meine Frage ist, was wird das Ändern dieser Spalten auf den Seiten und vorhandenen auf der Festplatte tun? (Es gibt viele Informationen darüber, was passiert, wenn Sie eine Spalte vergrößern, aber Probleme, Informationen darüber zu finden, was passiert, wenn Sie eine Spalte verkleinern.)

Einige der Tabellen haben eine sehr kleine Zeilenanzahl, daher mache ich mir keine Sorgen über die Kosten der Änderung, andere sind ziemlich groß, und ich mache mir Sorgen darüber, dass sie möglicherweise reorganisiert werden und eine Menge Blockierungs- / Ausfallzeiten verursachen. In der Praxis möchte ich nur ein Wartungsfenster abschätzen. Im Allgemeinen würde ich gerne besser verstehen, wie sich das Datenbankmodul in diesem Fall verhält.

Danke im Voraus!

BEARBEITEN:

Ich habe 20 Tische, die ich mir anschaue, obwohl nur die Hälfte von ihnen eine Zeilenzahl von mehr als 1.000 hat. Der größte hat fast eine Million Zeilen. Der schlimmste Übeltäter ist eine Tabelle mit 350.000 Zeilen und vier VARCHAR(MAX)Spalten, die auf das VARCHAR(500)Niveau geschrumpft werden kann .

Nateirvin
quelle

Antworten:

12

Das Wichtigste zuerst: Wie viele Daten enthält die Tabelle? Anzahl der Zeilen und Größe der Tabelle?

Zweitens: Können Sie diese Tabelle auf einem Testserver sichern und wiederherstellen und die alter-Anweisung ausführen, um die Auswirkungen zu ermitteln (vorausgesetzt, sie ist nicht unmöglich, da die Tabelle für ein Nichtproduktionssystem zu groß ist)? Ich finde immer, dass das Testen in meiner Umgebung genauer ist als die Empfehlungen aus den Interwebs, da es mehrere Faktoren gibt, die das Ergebnis beeinflussen können, die in der Frage möglicherweise nicht angegeben werden, weil nicht bekannt ist, dass diese Faktoren das Ergebnis beeinflussen können.

Drittens: Das Erhöhen der Größe eines Felds mit variabler Länge ist (vorausgesetzt, Sie überschreiten nicht die 8060-Byte-Grenze) eine einfache Metadatenoperation, da sich für eine solche Operation keine tatsächlichen Daten ändern würden. ABER auf der anderen Seite ist es keine einfache Metadatenänderung , die Größe eines Felds mit variabler Länge zu reduzieren , selbst wenn dies mehr als offensichtlich funktioniert, da SQL Server vor dem Durchsuchen aller Zeilen nicht weiß , dass die neu angeforderte Größe gültig ist.

Daher: Ja, dies sperrt die Tabelle für einen bestimmten Zeitraum . Wie viel Zeit? Nun, hier ist der Test, den ich gerade gemacht habe:

Aus anderen Tests ging hervor, dass ich eine Tabelle mit einem einzigen INT NOT NULLFeld und 1 Million Zeilen hatte. Ich habe es in eine neue Tabelle kopiert, um diesen Test durchzuführen:

SELECT *, CONVERT(NVARCHAR(MAX), NEWID()) AS [StringField]
INTO dbo.ResizeTest
FROM dbo.ClusteredUnique;

Auf diese Weise begann ich mit einem ähnlichen Szenario, in dem ich ein MAXFeld hatte (ich habe gerade festgestellt, dass Sie ein Feld haben VARCHARund das ich verwende NVARCHAR, aber das sollte das Verhalten, das ich sehe, nicht ändern), das ich dann ändern könnte 500. Und es enthält Daten, die problemlos in 500 Zeichen passen. Das hat ein paar Minuten gedauert.

Ich lief dann:

ALTER TABLE dbo.ResizeTest ALTER COLUMN [StringField] NVARCHAR(500) NULL;

Und das dauerte etwas mehr als 11 Minuten.

Ich habe den Test gerade noch einmal wiederholt, diesmal habe ich den [ResizeTest]Tisch fallen lassen und beide NVARCHARgeändert, um nur zu sein VARCHAR, um sicherzugehen, dass ich Äpfel mit etwas vergleiche, das zumindest wie ein Apfel aussieht ;-).

Die anfängliche Tabellenerstellung dauerte 20 Sekunden, während die Erstellung ALTER TABLE2 Minuten dauerte.

In Bezug auf die Schätzung der Ausfallzeit ist dies wirklich schwierig, da es auf den E / A-Geschwindigkeiten der Festplatte beruht und es keine automatischen Wachstumsvorgänge für die Datendatei und / oder das Transaktionsprotokoll usw. geben muss Dies ist wahrscheinlich ein wesentlicher Grund dafür, warum mein erster Test 11 Minuten in Anspruch nahm und der zweite, obwohl VARCHARer nur halb so groß war wie die NVARCHARDaten, nur 2 Minuten in Anspruch nahm (dh die Dateien wurden zu diesem Zeitpunkt vorgewachsen). Sie sollten jedoch bedenken, dass mein Test auf meinem Laptop ausgeführt wird, der nicht die schnellste Festplatte ist, aber es waren auch nur 1 Million Zeilen mit 2 kleinen Spalten (etwa 22 Byte pro Zeile).

Und da Sie gefragt haben, was es mit den Datenseiten machen soll, ist hier Ihre Antwort. Ich habe eine sp_spaceusednach dem Erstellen der Tabelle, nach dem Ausführen der ALTER COLUMNund nach dem Ausführen ALTER TABLE dbo.ResizeTest REBUILD;. Die Ergebnisse (die folgenden Zahlen basieren auf dem zweiten Test mit VARCHAR, nicht dem ersten Test mit NVARCHAR):

After initial table creation:        526,344 KB
After ALTER COLUMN VARCHAR(500):   1,031,688 KB  <--- !! Yikes!!
After ALTER REBUILD:                 526,472 KB

Wenn Sie Bedenken haben, den Vorgang so kurz wie möglich zu halten, lesen Sie einen Artikel, in dem ich genau das beschrieben habe: Restrukturieren Sie 100-Millionen-Zeilen-Tabellen (oder mehr) in Sekunden. SRSLY! (kostenlose Registrierung erforderlich).

Solomon Rutzky
quelle
2
Also habe ich die schlechteste Tabelle auf meine lokale Instanz kopiert (dh langsamere Festplatte und 1/3 der Kerne). Ich habe ALTERjede Spalte nacheinander bearbeitet - jede Aktion dauerte weniger als eine Sekunde. Als sie fertig waren, hatte sich die Größe des Tisches verdoppelt, aber als ich eine REBUILDOperation (die auch eine Operation unter einer Sekunde war) durchführte, kehrte der Tisch zu seiner ursprünglichen Größe zurück.
Nateirvin
@nateirvin Das ist gut zu hören. Sie können den ALTER TABLEVorgang wahrscheinlich beschleunigen, indem Sie alle Felder auf einmal ausführen und jede Spalte durch ein Komma trennen. Wenn die Transaktion zu groß ist, teilen Sie die Tabelle in 2 ALTER-Anweisungen mit jeweils der Hälfte der Spalten auf. Und je nachdem, wie groß die Tabelle wird, können Sie zwischen den beiden ALTER-Anweisungen sogar ein REBUILD durchführen. Etwas zum Spielen. Beachten Sie auch, dass die Operation wahrscheinlich für die Dauer eine Schemasperre benötigt, die den gesamten Zugriff auf die Tabelle blockiert.
Solomon Rutzky
1
Ich habe jedes für ALTERsich gemacht, um die Größenänderungen zwischen den einzelnen zu verfolgen, aber auf jeden Fall gut zu wissen. Vielen Dank!
Nateirvin
1

Soweit ich weiß, sollte die Ausführung der alter-Anweisung nicht sehr lange dauern, solange der Tisch nicht durch einen anderen Prozess gesperrt ist. Laut gbn handelt es sich lediglich um eine Metadatenänderung: /programming/7261909/is-it-bad-to-use-alter-table-to-resize-a-varchar-column-to-a-larger -Größe

Außerdem scheint es, als ob SQL Server die varchar-Daten in einer 8-KB-Seite gespeichert hat, bis sie eine ganze Seite ausfüllen. An diesem Punkt wird sie durch einen Zeiger ersetzt und als BLOB gespeichert.

Ich gehe davon aus, dass Sie beim Ändern der Länge keine Datensätze abschneiden. Wenn ja, sollten die Daten, die Sie in varchar (500) konvertieren, höchstens 502 Byte lang sein und keinen Zeiger haben.

Kurz gesagt, es sollte sich nicht viel ändern, solange Sie keine Daten abschneiden.

DForck42
quelle
5
Das ist absolut falsch. Ich werde nicht abstimmen, weil Sie es tatsächlich getestet haben (das ist mehr als manche Leute, also danke, dass Sie das getan haben), aber Sie müssen dies in größerem Maßstab testen. Bei der Antwort, auf die Sie verwiesen haben, ging es darum, die Größe zu erhöhen, nicht zu verringern. Das sind zwei sehr unterschiedliche Operationen.
Solomon Rutzky