it-swarm.com.de

Kann ich eine Masseneinfügung in eine leere, seitenkomprimierte Tabelle vornehmen und eine vollständige Komprimierung erhalten?

Ich habe viele große Tabellen (ungefähr 10 Millionen breite Zeilen), die regelmäßig in SQL Server 2016 geladen werden müssen, um schreibgeschützte Berichte zu erstellen. Ich möchte, dass diese Tabellen auf der Festplatte so klein wie möglich sind, und dies ist wichtiger als Leistungsverbesserungen beim Laden oder Abfragen.

Folgendes habe ich für die Tabellen getan, für die keine weitere Indizierung erforderlich ist:

  1. Erstellen Sie die Tabelle mit DATA_COMPRESSION=PAGE.
  2. Verwenden Sie bcp, um die Daten aus einer Flatfile in die neue Tabelle einzufügen.

Die Spaltentypen in den Tabellen sind varchar (niemals mehr als 512, nicht max), float, tinyint oder date (nicht datetime). Alle Spalten werden als nullwertfähig erstellt und es werden keine Primär- oder Fremdschlüssel definiert. Sie spielen für die Abfrage keine Rolle und die Tabellen werden niemals direkt aktualisiert. Die Standardkollatierung für alles ist SQL_Latin1_General_CP1_CI_AS.

Wenn ich das mache, kann ich in sys.allocation_units Sehen, dass die Seitendatenkomprimierung auf den Heap angewendet wurde, und ich kann in sys.partitions Sehen, dass der Füllfaktor korrekt 0 (100%) ist. Da die Tabellen viel kleiner sind als unkomprimierte Tabellen, dachte ich, dass die Komprimierung durchgeführt wurde.

Wenn ich dann aber mit der gleichen Option DATA_COMPRESSION=PAGE Neu erstelle, wird die angeblich bereits komprimierte Tabelle um 30% kleiner! Es sieht so aus, als würde es von ungefähr 17 Zeilen pro Datenseite auf 25 Zeilen pro Seite gehen. (Nur einmal. Ein erneuter Wiederaufbau macht ihn danach nicht kleiner als beim ersten Wiederaufbau.)

Die Fragen

Meine Fragen sind also: (a) Was ist hier los? und (b) gibt es eine Möglichkeit, diese extra kleine komprimierte Größe direkt beim Laden der Tabelle zu erhalten, ohne sie nach dem Laden der Daten neu erstellen zu müssen?

7
Caitlin M. Shaw

@ HandyD ist völlig korrekt. Ich möchte nur einige andere Methoden hervorheben, um die Komprimierung beim Einfügen in einen Heap zu erhalten.

Aus demselben Dokument

Wenn ein Heap für die Komprimierung auf Seitenebene konfiguriert ist, erhalten Seiten nur auf folgende Weise eine Komprimierung auf Seitenebene:

  • Daten werden mit aktivierten Massenoptimierungen als Massenimport importiert.
  • Daten werden mit der Syntax INSERT INTO ... WITH (TABLOCK) eingefügt, und die Tabelle hat keinen nicht gruppierten Index.
  • Eine Tabelle wird neu erstellt, indem die Anweisung ALTER TABLE ... REBUILD mit der Komprimierungsoption PAGE ausgeführt wird.

Demnach können Sie minimal protokollierte Masseneinfügungen nutzen oder INSERT INTO ... WITH (TABLOCK) verwenden, um PAGE Komprimierung zu erhalten, ohne Neuerstellungen durchführen zu müssen.


(a) Was ist hier los? und (b) gibt es eine Möglichkeit, diese extra kleine komprimierte Größe direkt beim Laden der Tabelle zu erhalten, ohne sie nach dem Laden der Daten neu erstellen zu müssen?

Es gibt Regeln, um beim Einfügen in einen Heap die Komprimierung PAGE zu erhalten. Fügen Sie Ihrem Befehl bcp-h "TABLOCK" Hinzu, um die Komprimierung zu erhalten.

ROW Die Komprimierung funktioniert ohne diese Voraussetzungen und ist die geringste Komprimierungsmenge, die in den folgenden Beispielen verwendet wird. Vielen Dank @ DenisRubashkin für den Hinweis!


Testen

Beispiel für einen Startdaten- und BCP-Out-Befehl


--Tested on SQL Server 2014 SP2

CREATE TABLE dbo.CompressedHeap_Source( Val varchar(512), 
                                 Datefield Date, 
                                 Tinyfield TinyINT,
                                 Floatfield float) 
WITH (DATA_COMPRESSION = PAGE);

INSERT INTO dbo.CompressedHeap_Source
(
Val,Datefield,Tinyfield,Floatfield)

SELECT 'Bla',cast(getdate() as date),1,1.2412
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2;

--bcp TEST.dbo.CompressedHeap_Source out E:\Data\HeapData.bcp -c -T

Die komprimierte und unkomprimierte Größe ROW

Die Datengröße liegt bei 132272 KB Bei einer Standardeinfügung in den Heap. Dies ist ROW komprimiert, aber nicht PAGE komprimiert.

Die Datengröße ohne Komprimierung beträgt für unseren Test ~ 176216 KB.

exec sp_spaceused 'dbo.CompressedHeap_Source'

name                    rows                    reserved    data      index_size    unused
CompressedHeap_Source   6365530                 132296 KB   132272 KB   8 KB    16 KB

INSERT IN ... WITH TABLOCK

Durch Einfügen von WITH TABLOCK Erhalten wir die komprimierte Datengröße PAGE69480 KB.

INSERT INTO dbo.CompressedHeap_Source2  WITH(TABLOCK)
(
Val,Datefield,Tinyfield,Floatfield)

SELECT 'Bla',cast(getdate() as date),1,1.2412
FROM master..spt_values spt1
CROSS APPLY master..spt_values spt2

BULK INSERT

Wenn wir nun eine Ziel-Heap-Tabelle erstellen, die ebenfalls page komprimiert ist, und eine Masseneinfügung with tablock Durchführen:

CREATE TABLE dbo.CompressedHeap_Destination( Val varchar(512), 
                                 Datefield Date, 
                                 Tinyfield TinyINT,
                                 Floatfield float) 
WITH (DATA_COMPRESSION = PAGE);

bulk insert dbo.CompressedHeap_Destination

from 'E:\Data\HeapData.bcp'  with (TABLOCK)

Die Daten werden page komprimiert und befinden sich ebenfalls bei 69480 KB:

name    rows    reserved    data    index_size  unused
CompressedHeap_Destination  6365530                 69512 KB    69480 KB    8 KB    24 KB

BCP IN MIT TABLOCK

Sie können die gleichen Ergebnisse wie beim BULK INSERT WITH TABLOCK Erhalten, indem Sie BCP IN Mit dem Hinweis -h "TABLOCK" Verwenden. Das macht Sinn, sie machen das auch intern

--bcp TEST.dbo.CompressedHeap_Destination2 IN E:\Data\HeapData.bcp -c -T -h "TABLOCK"

Die resultierende Größe ist 69480 KB

BCP IN OHNE TABLOCK

Verwenden von BCP zum Laden von Daten aus derselben Datei in eine Kopie der Zieltabelle

Ein Standard-Befehl bcp führt zu nicht komprimierten Daten:

--bcp TEST.dbo.CompressedHeap_Destination2 IN E:\Data\HeapData.bcp -c -T 

Mit der Datengröße bei 132272 KB (Zeile komprimiert).

8
Randi Vertongen

Laut dem Artikel Docs über Komprimierung:

Neue Seiten, die im Rahmen von DML-Vorgängen in einem Heap zugewiesen werden, verwenden die PAGE-Komprimierung erst, wenn der Heap neu erstellt wurde. Erstellen Sie den Heap neu, indem Sie die Komprimierung entfernen und erneut anwenden oder einen Clustered-Index erstellen und entfernen.

Dies scheint mit dem übereinzustimmen, was Sie sehen. Es scheint, als würden Sie erst dann eine Komprimierung auf dem Tisch erhalten, wenn Sie ihn neu erstellen. Sie können versuchen, die Daten in eine nicht komprimierte Tabelle zu laden und festzustellen, ob Sie durchschnittlich noch 17 Zeilen pro Seite haben oder ob dies abnimmt. Wenn es gleich bleibt, erhalten Sie keine Komprimierung und die Neuerstellung ist erforderlich.

Sie können Ihrer Tabelle auch einen Clustered-Index hinzufügen. Dies sollte verhindern, dass Ihre Tabelle nach dem Massenladen Ihrer Daten dekomprimiert/niedrig komprimiert wird.

5
HandyD