Der beste Weg, um eine Datenbank zu verkleinern, nachdem Daten von varbinary (max) auf Null gesetzt wurden?

8

Wir haben eine Datenbank mit einer großen Datenmenge, die in einem Feld vom Typ varbinary (max) gespeichert ist . Irgendwann können wir diese Daten für die meisten Zeilen löschen, aber nicht für alle. Unser Plan ist es, dieses Feld auf Null zu setzen und die Daten einfach auf Null zu setzen, wenn sie nicht mehr benötigt werden. Sobald wir das tun, möchten wir die Größe der Datenbank reduzieren. Was ist der beste Weg, um dies zu erreichen?

Wenn es mit dem aktuellen Setup keine gute Möglichkeit gibt, Speicherplatz zurückzugewinnen, besteht eine Idee darin, dieses Datenfeld in eine separate Tabelle mit nur zwei Spalten zu verschieben: den Schlüssel zur Haupttabelle und das Datenfeld. Dann könnten wir die Zeilen einfach löschen, wenn sie nicht mehr benötigt werden. (Und dann eine Art Verkleinerung durchführen.) Dies wäre jedoch eine viel schwierigere Änderung, als das vorhandene Feld einfach auf Null zu setzen.

Hinweis: Es ist mir eigentlich nicht so wichtig, die Datenbankdatei zu verkleinern, aber es ist mir wichtig, dass der neu freigegebene Speicherplatz wiederverwendbar wird.

Über 90% der DB-Größe sind dieses eine Feld. Ich bin schon bei 3 TB.

TTT
quelle

Antworten:

13

Für mich sieht es so aus, als würden nur die Spalten aktualisiert, NULLum Seiten zur Wiederverwendung freizugeben. Hier ist eine Very Scottish®-Demo, um zu feiern, dass es fast 17 Uhr EST ist.

USE tempdb;

DROP TABLE IF EXISTS dbo.RobertBurns;

CREATE TABLE dbo.RobertBurns
(
    Id INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    Scotch VARCHAR(50),
    HaggisAddress VARBINARY(MAX)
);

DECLARE @AddressToAVarbinaryHaggis VARBINARY(MAX); 
DECLARE @AddressToAHaggis NVARCHAR(MAX) = N'
Good luck to you and your honest, plump face,
Great chieftain of the pudding race!
Above them all you take your place,
        gut, stomach-lining, or intestine,
You''re well worth a grace
        as long as my arm.

The overloaded serving tray there you fill,
Your buttocks shaped like a distant hilltop,
Your wooden skewer could be used to fix a mill
         if need be,
While through your pores your juices drip
         like liquid gold.

His knife see the serving-man clean,
And then cut you up with great skill,
Making a trench in your bright, gushing guts
        To form a ditch,
And then, 0h! What a glorious sight!
        Warm, steaming, and rich!

Then, spoonful after spoonful, they eagerly eat,
The devil will get the last bit, on they go,
Until all their well-stretched stomachs, by-and-by,
        are bent like drums,
Then the head of the family, about to burst,
        murmurs “Thank the Lord".

Is there a pretentious soul who, over his French ragout,
Or Italian cuisine that would make a pig sick,
Or French stew that would make that same pig ill
        with complete and utter disgust,
Looks down with a sneering, scornful attitude,
        on such a meal? (as Haggis)

Poor devil! See him over his trash!
As feeble as a withered bullrush,
His skinny leg no thicker than a thin rope,
        His fist the size of a nut,
Through a river or field to travel,
        Completely unfit!

But look at the healthy, Haggis-fed person!
The trembling earth respects him as a man!
Put a knife in his fist,
        He''ll make it work!
And legs, and arms, and heads will come off,
        Like the tops of thistle.

You Powers who look after mankind,
And dish out his bill of fare,
Old Scotland wants no watery, wimpy stuff
        That splashes about in little wooden bowls!
But, if You will grant her a grateful prayer,
        Give her a Haggis!';


INSERT dbo.RobertBurns (Scotch, HaggisAddress )
SELECT TOP 1000 
CASE WHEN x.c % 15 = 0 THEN 'Laphroaig'
     WHEN x.c % 5 = 0 THEN 'Lagavulin'
     WHEN x.c % 3 = 0 THEN 'Port Ellen'
     ELSE 'Ardbeg'
END AS Scotch, 
CONVERT(VARBINARY(MAX), REPLICATE(@AddressToAHaggis, x.c % 20 + 1))
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY @@ROWCOUNT) AS c
FROM sys.messages AS m
) AS x;

CREATE INDEX ix_novarbinary ON  dbo.RobertBurns (Scotch, Id);
CREATE INDEX ix_yesvarbinary ON dbo.RobertBurns (Scotch, Id) INCLUDE (HaggisAddress);

Schauen wir uns mit eingefügten Zeilen unsere Indexseiten an.

SELECT   OBJECT_NAME(i.object_id) AS table_name,
         i.name AS index_name,
         MAX(a.used_pages) AS leaf_me_alone
FROM     sys.indexes AS i
JOIN     sys.partitions AS p
ON p.object_id = i.object_id
   AND p.index_id = i.index_id
JOIN     sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE OBJECT_NAME(i.object_id) = 'RobertBurns'
GROUP BY i.object_id, i.index_id, i.name
ORDER BY OBJECT_NAME(i.object_id), i.index_id;

Nach dem Einfügen bekomme ich das. Die tatsächlichen Seiten können für Sie variieren.

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5587
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5581

Lass uns ein NULLpaar Zeilen raus!

UPDATE rb
    SET rb.HaggisAddress = NULL
FROM dbo.RobertBurns AS rb
WHERE rb.Id % 15 = 0;

Und schauen Sie noch einmal auf unseren Seiten vorbei:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5300
RobertBurns ix_novarbinary                  10
RobertBurns ix_yesvarbinary                 5273

So wurde die Seitenzahl reduziert. Huzzah! Für die beiden Indizes, die unsere VARBINARYDaten berühren , haben sie ein paar Seiten verloren. Das bedeutet, dass sie wieder im Umlauf sind, damit andere Objekte verwendet werden können. Da ich in Tempdb bin, werden sie wahrscheinlich ziemlich schnell von all den Müllsachen verschlungen, die hier vor sich gehen.

Lassen Sie uns nun einige Daten wieder eingeben:

INSERT dbo.RobertBurns (Scotch, HaggisAddress )
SELECT TOP 10 rb.Scotch, rb.HaggisAddress
FROM dbo.RobertBurns AS rb;

Und wieder einchecken:

table_name  index_name                      leaf_me_alone
RobertBurns PK__RobertBu__3214EC074BE633A2  5330
RobertBurns ix_novarbinary                  11
RobertBurns ix_yesvarbinary                 5305

Die Seitenzahlen stiegen etwas an.

Sieht also so aus, als müssten Sie nichts zu Verrücktes tun oder sogar Ihre Datenbank verkleinern, um Speicherplatz wiederzuverwenden. Ich denke, Sie haben das Verhalten des Löschens von Spalten in Konflikt gebracht und mussten mit dem laufen, DBCC CLEANTABLEwas Sie tatsächlich tun.

Hoffe das hilft!

Erik Darling
quelle