it-swarm.com.de

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

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 insufficient disk space Erhalten.

Natürlich hat das Verkleinern der Datenbank und der Dateigruppe nicht geholfen. DBCC SHRINKDATABASE Hat nicht geholfen. Also habe ich eine einfache Anwendung geschrieben, um jeden Datensatz zu lesen, einige unerwünschte Teile des OriginalHtml -ähnlichen Kopfabschnitts und der Seiten- und Fußzeile zu entfernen, um nur den Hauptteil zu behalten, und ich sehe dieses Bild jetzt, wenn ich einen Bericht über die Datenträgernutzung von erhalte Top-Tische:

(enter image description here

So wie 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 Option truncateonly 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 
8
Saeed Neamati

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

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

Siehe ALTER INDEX (Transact-SQL)

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

Die Option LOB_COMPACTION Ist standardmäßig ON, aber es schadet nicht, explizit zu sein. Möglicherweise müssen Sie REORGANIZE wiederholt 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 den zugehörigen Fragen und Antworten Freigeben von nicht verwendetem Speicherplatz SQL Server Table ausprobieren

Wenn das oben Gesagte aus irgendeinem Grund für Sie nicht funktioniert, die Daten in eine Datei exportieren , die Tabelle abschneiden , dann lade es neu . Es gibt verschiedene Methoden, um dies zu erreichen, zum Beispiel das bcp-Dienstprogramm .

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 sys.dm_db_index_physical_stats DMV 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 output

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 output

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 output

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, die Tabellendaten mit xp_cmdshell In eine Datei zu exportieren. Wenn xp_cmdshell 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 Servernamen -S Ändern und möglicherweise Anmeldeinformationen angeben müssen.

So können wir die Tabelle abschneiden und mit BULK INSERT Neu laden:

-- 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 output

Das Obige ist nicht ganz so effizient, wie es aufgrund eines langjährigen Fehlers sein könnte: 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_cmdshell Oder bcp zu verwenden.

Zusätzliche Bemerkungen:

  • FILLFACTOR gilt nur für Indexseiten. Dies hat keinen Einfluss auf den LOB-Speicher außerhalb der Zeile (der nicht auf Indexseiten gespeichert ist).
  • Zeile und Seite Komprimierung sind nicht für die Speicherung außerhalb der Zeile verfügbar.
  • Alternativ können Sie Daten explizit mit den in SQL Server 2016 verfügbaren Funktionen COMPRESS und DECOMPRESS komprimieren und dekomprimieren.

    Eine Option für Benutzer von SQL Server 2014 (was hier der Fall ist) oder älter (bis zu SQL Server 2005), um dieselbe Komprimierungsfunktionalität zu erhalten, die von den integrierten Funktionen COMPRESS und DECOMPRESS bereitgestellt wird 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 Funktionen Util_GZip und Util_GUnzip sollten COMPRESS bzw. DECOMPRESS entsprechen. 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.

10
Paul White 9

Wenn Sie ein Upgrade auf SQL Server Express 2016 SP1 oder höher durchführen können, können Sie mit DATA COMPRESSION eine enorme Platzersparnis erzielen.

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 (%)

1
Scott Hodgin