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 ALL
obigen Namen durch diesen Namen.
Die LOB_COMPACTION
Option ist standardmäßig aktiviert ON
, aber es schadet nicht, explizit zu sein. Möglicherweise müssen Sie das 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 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_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';
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);
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);
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_cmdshell
dies 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 -S
Servernamen ä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:
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_cmdshell
oder zu verwenden bcp
.
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).
- 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 COMPRESS
und 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 COMPRESS
und DECOMPRESS
integrierten 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 COMPRESS
und 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.
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 dieCOMPRESS()
Funktion eingeführt, mit der das OP den gzip-Algorithmus verwenden kann, um die OriginalHTML-Daten in der Tabelle zu komprimieren.