So geben Sie den nicht genutzten Platz für einen Tisch frei


8

Diese Frage wird wie zehnmal gestellt, und zu meiner Überraschung ist eine so einfache Anforderung so schwierig. Dennoch kann ich dieses Problem nicht lösen.

Ich verwende SQL Server 2014 Express Edition mit einer Datenbankgröße von 10 GB (keine Dateigruppengröße, Datenbankgröße).

Ich habe Nachrichten gecrawlt und HTML in eine Tabelle eingefügt. Das Schema der Tabelle lautet:

Id bigint identity(1, 1) primary key,
Url varchar(250) not null,
OriginalHtml nvarchar(max),
...

Die Datenbank hat keine Größe mehr und ich habe sie erhalten insufficient disk space

Natürlich hat das Verkleinern der Datenbank und der Dateigruppe nicht geholfen. DBCC SHRINKDATABASEhat nicht geholfen. Also habe ich eine einfache Anwendung geschrieben, um jeden Datensatz zu lesen, einige unerwünschte Teile des OriginalHtmlähnlichen Kopfabschnitts sowie Seiten- und Fußzeilen zu entfernen, um nur den Hauptteil zu behalten, und ich sehe dieses Bild jetzt, wenn ich einen Bericht über die Festplattennutzung durch die oberen Tabellen erhalte:

Geben Sie hier die Bildbeschreibung ein

Soweit ich dieses Bild verstehe, entspricht der ungenutzte Speicherplatz jetzt 50 Prozent der Gesamtgröße. Das heißt, jetzt habe ich 5 GB ungenutzten Speicherplatz. Aber ich kann es nicht zurückfordern. Das Neuerstellen von Indizes hat nicht geholfen. Die truncateonlyOption hilft nicht weiter, da meines Wissens kein Datensatz gelöscht wird, sondern nur die Größe jedes Datensatzes reduziert wird.

Ich stecke an diesem Punkt fest. Bitte helfen Sie, was soll ich tun?

Der Clustered Index befindet sich in der Spalte Id.

Dies ist das Ergebnis von EXECUTE sys.sp_spaceused @objname = N'dbo.Articles', @updateusage = 'true';

name        rows     reserved     data        index_size   unused
----------- -------- ------------ ----------- ------------ -----------
Articles    112258   8079784 KB   5199840 KB  13360 KB     2866584 KB 

Antworten:


10

Wenn alle Dinge gleich sind, sollte es ausreichen, die LOB-Spalte (Large Object) zu komprimieren OriginalHTML. Sie geben den Clustered-Indexnamen in der Frage nicht an, also:

ALTER INDEX ALL
ON dbo.Articles
REORGANIZE 
WITH (LOB_COMPACTION = ON);

Sehen ALTER INDEX (Transact-SQL)

Wenn Sie den Namen des Clustered-Index haben (nicht nur die Clustered-Spalte (n)), ersetzen Sie den ALLobigen Namen durch diesen Namen.

Die LOB_COMPACTIONOption ist standardmäßig aktiviert ON, aber es schadet nicht, explizit zu sein. Möglicherweise müssen Sie das REORGANIZEwiederholt ausführen , um den gesamten nicht verwendeten Speicherplatz zurückzugewinnen.

Leider bedeutet die Art und Weise, wie LOB-Daten organisiert sind und wie LOB-Komprimierung implementiert ist, dass diese Methode möglicherweise nicht immer den gesamten nicht verwendeten Speicherplatz zurückgewinnen kann, unabhängig davon, wie oft Sie sie ausführen. Es kann auch sehr langsam sein.

Sie können die Methode auch in der zugehörigen SQL Server-Tabelle zur Freigabe von nicht verwendetem Speicherplatz ausprobieren

Wenn dies aus irgendeinem Grund für Sie nicht funktioniert, exportieren Sie die Daten in eine Datei, schneiden Sie die Tabelle ab und laden Sie sie erneut. Es gibt verschiedene Methoden, um dies zu erreichen, zum Beispiel das Dienstprogramm bcp .

Beispiel

Im Folgenden wird eine Tabelle mit 10.000 breiten Zeilen erstellt:

CREATE TABLE dbo.Test 
(
    c1 bigint IDENTITY NOT NULL, 
    c2 nvarchar(max) NOT NULL,

    CONSTRAINT PK_dbo_Test
        PRIMARY KEY CLUSTERED (c1)
);

-- Load 10,000 wide rows
INSERT dbo.Test WITH (TABLOCKX)
    (c2)
SELECT TOP (10000)
    REPLICATE(CONVERT(nvarchar(max), 'X'), 50000)
FROM master.sys.columns AS C1
CROSS JOIN master.sys.columns AS C2;

Wir können die Speicherplatznutzung mit der sys.dm_db_index_physical_statsDMV sehen:

SELECT
    DDIPS.index_id,
    DDIPS.partition_number,
    DDIPS.index_type_desc,
    DDIPS.index_depth,
    DDIPS.index_level,
    DDIPS.page_count,
    DDIPS.avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats
(
    DB_ID(),
    OBJECT_ID(N'dbo.Test', N'U'),
    1,
    NULL,
    'DETAILED'
) AS DDIPS
WHERE 
    DDIPS.alloc_unit_type_desc = N'LOB_DATA';

DMV-Ausgang

Wir aktualisieren jetzt den LOB-Inhalt auf eine kleinere Größe (die jedoch noch Speicher außerhalb der Zeile erfordert):

-- Change LOB data to a smaller value (that will not move in-row)
UPDATE dbo.Test WITH (TABLOCKX)
SET c2 = REPLICATE(CONVERT(nvarchar(max), 'Y'), 5000);

DMV-Ausgang

Beachten Sie, dass etwas Speicherplatz zurückgefordert wurde, die verbleibenden Seiten jedoch viel weniger voll sind als sie waren.

Wir können den LOB-Raum komprimieren, indem wir:

ALTER INDEX PK_dbo_Test ON dbo.Test 
REORGANIZE 
WITH (LOB_COMPACTION = ON);

DMV-Ausgang

Dies führt zu einer gewissen Verdichtung und Platzersparnis, ist jedoch nicht perfekt. Ein erneutes Ausführen der Verdichtung kann die Situation verbessern oder nicht. In meinem Test war dies nicht der Fall, egal wie oft ich es erneut ausgeführt habe.

Exportieren, kürzen, neu laden

Eine Möglichkeit, dies vollständig in Management Studio zu tun, besteht darin xp_cmdshell, die Tabellendaten in eine Datei zu exportieren. Wenn xp_cmdshelldies derzeit nicht aktiviert ist, wird Folgendes ausgeführt:

-- Enable xp_cmdshell if necessary
EXECUTE sys.sp_configure
    @configname = 'show advanced options',
    @configvalue = 1;

RECONFIGURE;

EXECUTE sys.sp_configure
    @configname = 'xp_cmdshell',
    @configvalue = 1;

RECONFIGURE;

Jetzt können wir den Export durchführen:

-- Export table
EXECUTE sys.xp_cmdshell
    'bcp Sandpit.dbo.Test out c:\temp\Test.bcp -n -S .\SQL2017 -T';

Beachten Sie, dass Sie den Pfad und den -SServernamen ändern und möglicherweise Anmeldeinformationen angeben müssen.

So können wir die Tabelle abschneiden und neu laden, indem wir BULK INSERT:

-- Truncate
TRUNCATE TABLE dbo.Test;

-- Switch to BULK_LOGGED recovery model if currently set to FULL
-- Bulk load
BULK INSERT dbo.Test
FROM 'c:\temp\Test.bcp' 
WITH 
(
    DATAFILETYPE = 'widenative', 
    ORDER (c1), 
    TABLOCK,
    KEEPIDENTITY
);

Der letzte Schritt besteht darin, den Identitäts-Seed zurückzusetzen:

-- Check and reseed identity
DBCC CHECKIDENT('dbo.Test', RESEED);

Diese Abfolge von Vorgängen ist normalerweise schneller als die LOB-Verdichtung und sollte immer zu optimalen Ergebnissen führen:

DMV-Ausgang

Das Obige ist nicht ganz so effizient, wie es aufgrund eines langjährigen Fehlers sein könnte: Die Spalte BULK INSERT with IDENTITY erstellt einen Abfrageplan mit SORT . Die dort aufgeführte Problemumgehung ist effektiv, aber ich würde mich nur darum kümmern, wenn die Tabelle sehr groß ist.

Vergessen Sie nicht, die temporäre Datei zu löschen, in der die exportierten Daten gespeichert sind.

Es steht Ihnen natürlich frei, den für Sie am besten geeigneten Massenexport- / Importansatz zu verwenden. Es ist nicht erforderlich, xp_cmdshelloder zu verwenden bcp.

Zusätzliche Bemerkungen:

  • FILLFACTORgilt nur für Indexseiten . Dies hat keinen Einfluss auf den LOB-Speicher außerhalb der Zeile (der nicht auf Indexseiten gespeichert ist).
  • Zeilen- und Seiten Kompression ist nicht für die Off-Reihe Speicherung zur Verfügung.
  • Alternativ können Sie Daten explizit mit den in SQL Server 2016 verfügbaren Funktionen COMPRESSund komprimieren und dekomprimieren DECOMPRESS.

    Eine Option für die Verwendung von SQL Server 2014 (was hier der Fall ist) oder älter (bis hinunter zu SQL Server 2005) die gleiche Kompressionsfunktionalität durch die zur Verfügung gestellt zu bekommen COMPRESSund DECOMPRESSintegrierten Funktionen ist SQLCLR zu verwenden. Vorgefertigte Funktionen, die genau dies tun, sind in der kostenlosen Version von SQL # verfügbar, die von Solomon Rutzky geschrieben wurde . Die Util_GZip und Util_GUnzip Funktionen sollten gleichwertig sein COMPRESSund DECOMPRESS, respectively. Jeder, der SQL Server 2012 oder höher verwendet, sollte sicherstellen, dass der Server, auf dem SQL Server ausgeführt wird, mit .NET Framework Version 4.5 oder neuer aktualisiert wird, damit der stark verbesserte Komprimierungsalgorithmus verwendet wird.


1

Wenn Sie ein Upgrade auf SQL Server Express 2016 SP1 oder höher durchführen können, können Sie mithilfe von DATA COMPRESSION eine enorme Menge an Platz sparen .

Möglicherweise haben Sie andere Dinge im Spiel, die Ihre Datenbank aufblähen. Wie aus dem Kommentar von Dan Guzman hervorgeht, sollten Sie jedoch den Füllfaktor aller Ihrer Indizes überprüfen.

Alles andere als 0 (Null) oder 100 bedeutet, dass SQL Server beim Erstellen (oder Wiederherstellen) des Index jede Seite nur bis zum Prozentsatz des Füllfaktors füllte. Wenn Sie beispielsweise einen Füllfaktor von 50 hätten, würden während der Indexerstellung / -wiederherstellung nur 50 Prozent der Seite gefüllt, was im Grunde den doppelten Speicherplatz verdoppeln würde, der zum tatsächlichen Speichern der Daten erforderlich ist.

Abrufen einer Abfrage aus dem Beitrag Füllfaktoren für Indizes in einer SQL Server-Datenbank suchen

Wenn Sie alle Indizes für alle Benutzertabellen in einer SQL Server-Datenbank suchen möchten, deren Füllfaktor sich von 0 oder 100 unterscheidet:

SELECT DB_NAME() AS Database_Name
, sc.name AS Schema_Name
, o.name AS Table_Name
, o.type_desc
, i.name AS Index_Name
, i.type_desc AS Index_Type
, i.fill_factor
FROM sys.indexes i
INNER JOIN sys.objects o ON i.object_id = o.object_id
INNER JOIN sys.schemas sc ON o.schema_id = sc.schema_id
WHERE i.name IS NOT NULL
AND o.type = 'U'
AND i.fill_factor not in (0, 100)
ORDER BY i.fill_factor DESC, o.name

Weitere wertvolle Informationen zum Füllfaktor finden Sie unter

5 Dinge über Fillfactor

Blitz Ergebnis: Füllfaktor (%)


2
Ein wichtiger Hinweis zu DATA_COMPRESSION. Durch die Komprimierung werden keine Daten komprimiert, die außerhalb der Zeile gespeichert sind, z. B. LOB-Daten oder ROW_OVERFLOW-Daten. In diesem Fall würden nur die ID- und URL-Spalten komprimiert - wahrscheinlich keine signifikanten Einsparungen. 2016 wird jedoch auch die COMPRESS()Funktion eingeführt, mit der das OP den gzip-Algorithmus verwenden kann, um die OriginalHTML-Daten in der Tabelle zu komprimieren.
Zwei

Vielen Dank für diese Anfrage. Ich habe es ausgeführt und es wurde keine Ergebnismenge zurückgegeben. Also kein anderer Füllfaktor als 0 oder 100.
Saeed Neamati
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.