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


7

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 (nie 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. Standardkollatierung für alles ist SQL_Latin1_General_CP1_CI_AS.

Wenn ich dies tue, kann ich auf sys.allocation_unitsdieser Seite sehen, dass die Datenkomprimierung auf den Heap angewendet wurde, und ich kann sehen, sys.partitionsdass 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 jedoch mit derselben Option neu erstelle DATA_COMPRESSION=PAGE, wird die angeblich bereits komprimierte Tabelle um etwa 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?

Antworten:


8

@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.

Nach diesem, könnten Sie minimal protokollierte Masseneinsätze oder die Verwendung nutzen INSERT INTO ... WITH (TABLOCK) zu bekommen PAGEKompression ohne Umbauten zu tun.


(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 zum PAGEKomprimieren beim Einfügen in einen Heap. Fügen Sie -h "TABLOCK"Ihrem bcpBefehl hinzu, um die Komprimierung zu erhalten.

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


Testen

Beispiel für den Befehl start data & BCP out


--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 ROWkomprimierte und unkomprimierte Größe

Die Datengröße ist bei 132272 KBeiner Standardeinfügung in den Heap angegeben. Diese wird ROWkomprimiert, aber nicht PAGEkomprimiert.

Die Datengröße ohne Komprimierung ist ~ 176216 KBfür unseren Test.

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 ... MIT TABLOCK

Durch das Einfügen erhalten WITH TABLOCKwir die PAGEkomprimierte Datengröße 69480 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 pagekomprimiert ist, und eine Masseneinfügung durchführen with tablock:

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 pagekomprimiert und befinden sich auch unter 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 das erhalten , BULK INSERT WITH TABLOCKindem Sie BCP INmit dem -h "TABLOCK"Hinweis. Das macht Sinn, sie machen das auch intern

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

Mit der resultierenden 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).


2
Ich denke, dass das Neuerstellen der "komprimierten" Tabelle ihre Größe verringern wird. Es scheint, dass die Tabelle ROW-komprimiert ist und neu erstellt werden muss, um PAGE zu komprimieren.
Denis Rubashkin

@DenisRubashkin Vielen Dank! Sie haben Recht, diese sind nicht unkomprimiert, sondern in der Tat zeilenkomprimiert. Mein schlechtes
Randi Vertongen

Ich habe die Antwort aktualisiert, nochmals vielen Dank!
Randi Vertongen

Du hast recht! Das Hinzufügen des -h TABLOCK zum Befehl bcp machte den Unterschied! Es scheint jetzt so offensichtlich, dass Sie darauf hingewiesen haben, aber ich habe es vorher völlig verpasst. (Eigentlich folgende Frage: Gibt es eine Möglichkeit zu sagen, dass es nur zeilenkomprimierte Daten in einer Tabelle mit einer Zuordnung für die Seitenkomprimierung gibt?)
Caitlin M. Shaw

2
Randi: nette Antwort :-). @ CaitlinM.Shaw (und Randi): Das ist eine gute Frage. Ja, es gibt eine Möglichkeit zu sagen. Wenn Sie diese Frage posten und dann hier in einem Antwortkommentar einen Link dazu posten (bitte verwenden Sie meinen @Namen, damit ich benachrichtigt werde), werde ich die Antwort posten.
Solomon Rutzky

5

Laut dem Docs- Artikel zur 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 wird. 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, der verhindern soll, dass Ihre Tabelle nach dem Massenladen Ihrer Daten dekomprimiert / niedrig komprimiert wird.

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.