Wie hoch ist der Zeilenaufwand bei Verwendung der Seitenkomprimierung?

10

Ich habe eine Tabelle mit 650 numerischen (19,4) Spalten erstellt. Wenn ich die Seitenkomprimierung einschalte, indem ich laufe

ALTER TABLE fct.MyTable REBUILD  WITH (DATA_COMPRESSION = PAGE);

Ich bekomme

Meldung 1975, Ebene 16,
Status 1 Index 'PK_Mytable' Zeilenlänge überschreitet die maximal zulässige Länge von '8060' Bytes.

650 mal 9 Bytes sind jedoch nur 5850 Bytes, was ziemlich weit von der angegebenen Grenze von 8060 Bytes entfernt ist.

Auf dem Server wird Windows 2012 r2 mit SQL Server 2016 SP1 CU2 ausgeführt

Wie hoch ist der Zeilenaufwand bei Verwendung der Seitenkomprimierung?

Hier ist ein Code, der zeigt, was ich meine:

/* test script to demo MSG 1975 */
DECLARE @sql NVARCHAR(max)='', @i INT =0
drop table if exists dbo.mytable;

SET @sql = 'Create table dbo.Mytable (MyTableID bigint not null 
  identity(1,1) primary key clustered, '

WHILE @i < 593 BEGIN
    SET @sql += ' Column' + LTRIM(@i) + ' numeric(19,4) null, '
    SET @i +=1
END

SET @sql += ' LastColumn int) '
--SET @sql += ' with (DATA_COMPRESSION = ROW) '
SET @sql += ' with (DATA_COMPRESSION = PAGE) '

SELECT @sql
EXEC sys.sp_executesql @sql

SELECT top 10000 * FROM dbo.MyTable MT

Die Zeilenkomprimierung schlägt ebenfalls fehl, jedoch mit einer anderen Zeilenanzahl.

Henrik Staun Poulsen
quelle
Wie groß ist Ihr Primärschlüssel? Wenn es sich um eine Faktentabelle handelt und Sie die Leistung komprimieren und verbessern möchten, empfehlen wir Ihnen, sich über Columnstore-Indizes zu informieren. Diese können erhebliche Auswirkungen haben. Über der Seitenkomprimierung liegt eine höhere CPU-Auslastung zum Dekomprimieren.
Stijn Wynants
@StijnWynants; 8 Bytes werden für BigInts verwendet. Dies ist in der Tat eine Tatsache, aber es kommen nicht genügend Zeilen herein, um einen Spaltenspeicherindex zu rechtfertigen.
Henrik Staun Poulsen

Antworten:

13

Wenn Sie versuchen, Ihre Tabelle ohne die gruppierte PK-Einschränkung zu erstellen, wird ein etwas anderer Fehler angezeigt:

Meldung 1701, Ebene 16, Status 1, Zeile 1 Das Erstellen oder Ändern der Tabelle 'Mytable' ist fehlgeschlagen, da die minimale Zeilengröße 8067 betragen würde, einschließlich 1530 Byte internem Overhead. Dies überschreitet die maximal zulässige Tabellenzeilengröße von 8060 Byte.

In dieser Fehlermeldung sehen Sie, dass 1530 Byte interner Overhead für die Seitenkomprimierung vorhanden sind.

Jetzt können Sie rechnen:

  • 8 Bytes für bigintMyTableID
  • 4 Bytes für intLastColumn
  • 9 Bytes für jede der 593 numeric(19,4)Spalten (insgesamt 5337 Bytes)
  • 1530 Byte Komprimierungsaufwand

Also, 8 + 4 + (593 * 9) + 1530 = 6879. Moment mal ... Das ist immer noch unter 8060. Was ist damit los?!


Der Seitenkomprimierungsalgorithmus stapelt tatsächlich mehrere Komprimierungsalgorithmen zusammen. Der erste Schritt besteht darin, die ROW-Komprimierung anzuwenden. Der Overhead der Zeilenkomprimierung ist nicht in den in dieser Fehlermeldung aufgeführten 1530 Bytes Overhead enthalten.

Weitere Informationen zur Funktionsweise der Zeilenkomprimierung finden Sie hier in meinem Blog und hier in BOL . Sie werden im BOL-Artikel feststellen, dass der numericSpeicher als "Dieser Speicher entspricht genau dem vardezimalen Speicherformat" beschrieben wird, dies wird jedoch nicht erläutert vardecimal. Dieser Beitrag behandelt vardecimaletwas mehr - im Wesentlichen werden 2 Byte Overhead pro Spalte hinzugefügt, um die tatsächliche Länge zu speichern (ähnlich wie bei der varcharAusführung).

Die Zeilenkomprimierung erfordert zusätzliche 2 Bytes für jede der 593 numericSpalten sowie die bigintund interfordert jeweils 1 Byte Overhead.

Die zeilenkomprimierten Speicheranforderungen wären:

  • 8 Bytes + 1 Byte Overhead für bigintMyTableID
  • 4 Bytes + 1 Byte Overhead für intLastColumn
  • 9 Bytes + 2 Bytes Overhead für jede der 593 numeric(19,4)Spalten
  • 1188 Byte ROW-Komprimierungsaufwand

8 + 4 + (593 * 9) = 5349 Byte Daten

1 + 1 + (593 * 2) = 1188 Byte Zeilenkomprimierungsaufwand

Insgesamt 6537 Byte für zeilenkomprimiertes Schema


Nachdem wir die Zeilengröße für das zeilenkomprimierte Schema haben, können wir unsere Mathematik erneut überprüfen. Die seitenkomprimierte Zeilengröße entspricht der Datengröße + dem Zeilenkomprimierungsaufwand + dem Seitenkomprimierungsaufwand:

  • 8 Bytes für bigintMyTableID
  • 4 Bytes für intLastColumn
  • 9 Bytes für jede der 593 numeric(19,4)Spalten
  • 1188 Byte ROW-Komprimierungsaufwand
  • 1530 Byte PAGE-Komprimierungsaufwand
  5349 Bytes Daten 
+ 1188 Byte Zeilenkomprimierungsaufwand 
+ 1530 Bytes Seitenkomprimierungsaufwand 

8067 Bytes insgesamt

Zwei
quelle
1
Ich mag Ihre Schlussfolgerung: "In den meisten Fällen werden Sie feststellen, dass durch die Zeilenkomprimierung etwas Platz gespart werden kann - aber nicht immer." 2718 Bytes Overhead sind viel mehr als ich erwartet hatte. Vielen Dank, dass Sie sich die Zeit genommen haben, eine so detaillierte Antwort zu schreiben.
Henrik Staun Poulsen
1
@HenrikStaunPoulsen Ein weiterer wichtiger Punkt ist, dass SQL Server davon ausgehen muss, dass Ihre Daten möglicherweise nicht komprimiert werden können. Selbst wenn Ihre Daten auf weniger als 8060 Byte komprimiert würden, muss SQL Server die Zeilengrößenberechnungen basierend auf der theoretischen maximalen Zeilengröße für nicht komprimierbare Daten durchführen.
Zwei
Nach 3 Tagen bin ich immer noch erstaunt über die Anzahl der für die Zeilenkomprimierung erforderlichen Bytes. 2 Bytes pro Spalte. Die Seitenkomprimierung fügt zusätzlich fast 3 Bytes hinzu. Aber; Danke für deine Hilfe. Es war sehr nützlich.
Henrik Staun Poulsen