Freigeben von nicht verwendetem Speicherplatz SQL Server-Tabelle

11

Ich habe eine Tabelle in SQL Server 2012 Express mit viel nicht verwendetem Speicherplatz.

Ich muss Speicherplatz in der Datenbank freigeben.

| NAME | REIHEN | RESERVIERT | DATEN | INDEX_SIZE | UNBENUTZT |
| ------------- | -------- | -------------- | ----------- --- | ------------ | -------------- |
| MyTableName | 158890 | 8928296 KB | 5760944 KB | 2248 KB | 3165104 KB |

Wie bringe ich SQL dazu, die 3165104KB freizugeben?

Ich habe es bereits versucht:

Alter table MyTableName Rebuild
DBCC CLEANTABLE (MyDbName,"MyTableName ", 0)
ALTER INDEX ALL ON MyTableName REORGANIZE ; 
ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF) 

Hier ist die Tabelle:

CREATE TABLE [dbo].[MyTableName](
    [ImageID] [int] IDENTITY(1,1) NOT NULL,
    [DateScan] [datetime] NULL,
    [ScanImage] [image] NULL,
 CONSTRAINT [PK_Image] PRIMARY KEY CLUSTERED 
(
    [ImageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Das einzige, was wir getan haben, ist, ScanImagein jeder Zeile durch ein viel kleineres Bild zu ersetzen (so viel ungenutzter Speicherplatz ist vorhanden).

DermFrench
quelle

Antworten:

10

Das einzige, was wir getan haben, ist, ScanImagein jeder Zeile durch ein viel kleineres Bild zu ersetzen (so viel ungenutzter Speicherplatz ist vorhanden).

Nach einigen Experimenten besteht die platzsparendste Methode darin, die Zuordnungseinheit zu löschen und neu zu füllen (wenn Sie ein Wartungsfenster haben, in dem Sie dies tun können).

Beispielcode, der mit der Tabellenstruktur in der Frage die beste Speicherplatzreduzierung für mich erzielt hat, lautet:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET XACT_ABORT ON;

BEGIN TRAN

SELECT [ImageID],
       [ScanImage]
INTO   #Temp
FROM   [dbo].[MyTableName]

ALTER TABLE [dbo].[MyTableName]
  DROP COLUMN [ScanImage]

/*Allocation unit not removed until after this*/
ALTER INDEX PK_Image ON MyTableName REBUILD

ALTER TABLE [dbo].[MyTableName]
  ADD [ScanImage] IMAGE NULL

UPDATE [dbo].[MyTableName]
SET    [ScanImage] = T.[ScanImage]
FROM   [dbo].[MyTableName] M
       JOIN #Temp T
         ON M.ImageID = T.[ImageID]

DROP TABLE #Temp

COMMIT 

Alles befindet sich in einer Transaktion. Wenn die Maschine abstürzt, wird sie zurückgesetzt. Könnte wahrscheinlich mit einer Fehlerbehandlung oder zumindest zu tun haben SET XACT_ABORT ON. Ich habe immer SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;verhindert, dass während oder nach dem Kopieren gleichzeitig Änderungen vorgenommen werden und verloren gehen.

Die Anzahl der LOB-Seiten, die nach dem Reduzieren der Größe von a imagein allen Zeilen reserviert wurden, war wie folgt:

+ --------------------------------------------- - + --------------------- + ------------------------- +
| Ereignis | lob_used_page_count | lob_reserved_page_count |
+ --------------------------------------------- - + --------------------- + ------------------------- +
| 10.000 Zeilen mit jeweils 100.000 Byte Daten eingefügt | 135005 | 135017 |
| Alle Zeilen wurden auf 10.000-Byte-Bilddaten aktualisiert 31251 | 135012 |
| Reorganisieren | 23687 | 25629 |
| Bilddaten löschen und erneut hinzufügen | 13485 | 13489 |
+ --------------------------------------------- - + --------------------- + ------------------------- +
Martin Smith
quelle
1
Oder wenn die Tabelle groß ist, dann BCP-Out-Daten und dann BULK INSERT wieder rein - während des Wartungsfensters.
Kin Shah
6

Versuchen

ALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF)

Dadurch wird der Clustered-Index neu erstellt, sodass Sie zusätzlichen Speicherplatz in Ihrer Datenbank benötigen, damit der Vorgang abgeschlossen werden kann. Wenn Sie keinen zusätzlichen Platz haben, weil Ihre Festplatte voll ist, können Sie möglicherweise eine neue Datendatei zur Datenbank hinzufügen (auf einer anderen Festplatte) und die Tabelle dorthin verschieben.

Es ist auch möglich, dass der Clustered-Index mit einem FILLFACTOR von weniger als 100% definiert wird. Wenn der Füllfaktor auf beispielsweise 66% eingestellt ist, bleibt 1/3 jeder Datenseite für die zukünftige Verwendung leer. Wenn dies das Problem ist, können Sie den Füllfaktor mithilfe von ändernALTER INDEX PK_Image ON MyTableName REBUILD WITH (ONLINE = OFF, FILLFACTOR=100)

Wenn Sie kürzlich ein Feld mit variabler Länge aus der Tabelle entfernt haben, können Sie es auch versuchen DBCC CLEANTABLE( Databasename, "MyTableName")

Books online (BOL) bietet unter http://technet.microsoft.com/en-us/library/ms188388%28v=sql.100%29.aspx einen großartigen Artikel zum Wiederherstellen von Indizes

Max Vernon
quelle
2

Stellen Sie sicher, dass der DB-Wiederherstellungsmodus aktiviert ist SIMPLE.

Ändern Sie die Spalte als VARBINARY(MAX).

Versuchen Sie dann, die Daten in eine völlig neue Tabelle zu kopieren.

Überprüfen Sie die neue Tabellengröße mit sp_spaceused "tablename". Wenn Sie mit dem nicht verwendeten Speicherplatz der Tabelle zufrieden sind, überprüfen Sie den nicht verwendeten Speicherplatz der Datenbank mit demselben Befehl, ohne einen Tabellennamen anzugeben. Dieser Speicherplatz befindet sich noch in den Datenbankdateien und wird nicht für das Betriebssystem freigegeben.

Sie können die ursprüngliche Tabelle löschen und die neue Tabelle umbenennen oder dasselbe erneut tun und den ursprünglichen Tabellennamen verwenden, wenn Sie dem Umbenennungsvorgang nicht vertrauen (ich vertraue nicht vollständig).

Wenn dies funktioniert, ist der letzte Schritt einfach: Sie wissen, wie Sie Dateien verkleinern und nicht genutzten Speicherplatz freigeben.

Wenn Fremdschlüssel vorhanden sind, zeichnen Sie deren Definitionen auf, löschen Sie sie, führen Sie die oben genannten Aufgaben aus und erstellen Sie die Fremdschlüssel anschließend neu. Dies wird natürlich einige Zeit dauern und dieser Vorgang sollte in Ruhezeiten durchgeführt werden. Diese ganze Aufgabe kann auch über ein Skript ausgeführt werden, damit sie über Nacht ausgeführt werden kann.

Anup Shah
quelle
1

Ich würde einfach eine neue Datenbank erstellen und die Daten darauf kopieren. Sie sollten den Import / Export-Assistenten verwenden können. (Offensichtlich würde eine Sicherung und Wiederherstellung das Problem beibehalten.) Überprüfen Sie die Ergebnisse des Imports der Daten. Wenn alles gut aussieht, benennen Sie die ursprüngliche Datenbank um und benennen Sie die neue Datenbank in den Namen um, den Sie verwenden möchten. (Ich warte immer ein bisschen, bevor ich das Original ablege, nur um es online noch einmal zu überprüfen.)

Für das, was es wert ist, haben wir durch die folgenden Schritte auch Blob-Speicherplatz aus Datenbanken zurückgefordert, wenn diese nicht zu groß sind. (Da Sie jedoch SQL Server Express verwenden, haben Sie möglicherweise keinen Platz, um dies zu versuchen.)

  1. Fügen Sie der Dateigruppe eine neue Datei hinzu.
  2. Ausführen DBCC SHRINKFILE(file, EMPTYFILE). Da Sie das MDF verkleinern, schlägt es schließlich fehl, da die Systemmetadaten nicht verschoben werden können. Die leeren Blob-Zuordnungen werden jedoch nicht verschoben.
  3. Ausführen DBCC SHRINKFILE(newfile,EMPTYFILE). Dadurch werden die Daten abzüglich des überschüssigen Speicherplatzes zurück verschoben.
  4. Löschen Sie die neue Datei (jetzt leer) aus der Dateigruppe.

Dies beseitigt das Aufblähen des Blobs. Ich sollte erwähnen, dass wir diese Technik hauptsächlich verwendet haben, um eine größtenteils leere Datenbank zum Testen von Upgrade-Skripten zu erstellen.

RLF
quelle
-1

Reorganisieren Sie den Clustered-Index - dieser hat die Daten an den Knoten, also ... ist er wahrscheinlich fragmentiert.

TomTom
quelle
Ich habe versucht auszuführen: ALTER INDEX ALL ON [MyTableName] REORGANIZE;
DermFrench
3
Bauen Sie es neu auf;) Nicht neu organisieren.
TomTom