Quelle est la surcharge de ligne lors de l'utilisation de la compression de page?

10

J'ai créé un tableau avec 650 colonnes numériques (19,4). Lorsque j'active la compression de page, en exécutant

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

Je reçois

Msg 1975, Level 16, State 1
Index 'PK_Mytable' la longueur de la ligne dépasse la longueur maximale autorisée de '8060' octets.

mais 650 fois 9 octets n'est que de 5850 octets, ce qui est assez loin de la limite indiquée de 8060 octets.

Le serveur exécute Windows 2012 R2 avec SQL Server 2016 SP1 CU2

Quelle est la surcharge de ligne lors de l'utilisation de la compression de page?

Voici un code pour montrer ce que je veux dire:

/* 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

La compression des lignes échoue également, mais à un nombre de lignes différent.

Henrik Staun Poulsen
la source
Quelle est la taille de votre clé primaire? S'il s'agit d'une table de faits et que vous souhaitez compresser et améliorer les performances, je vous suggère de lire les index columnstore, ils peuvent avoir un impact considérable. La surcharge de la page est plus utilisée par le processeur pour décompresser.
Stijn Wynants
@StijnWynants; 8 octets sont utilisés pour BigInts. C'est en effet un fait, mais il n'y a pas suffisamment de lignes entrant pour justifier un index columnstore.
Henrik Staun Poulsen

Réponses:

13

Si vous essayez de créer votre table sans la contrainte PK en cluster, et vous obtiendrez une erreur légèrement différente:

Msg 1701, niveau 16, état 1, ligne 1 La création ou la modification de la table 'Mytable' a échoué car la taille de ligne minimale serait 8067, y compris 1530 octets de surcharge interne. Cela dépasse la taille de ligne de table maximale autorisée de 8060 octets.

Dans ce message d'erreur, vous pouvez voir qu'il y a 1530 octets de surcharge interne pour la compression de page.

Maintenant, vous pouvez faire le calcul:

  • 8 octets pour bigintMyTableID
  • 4 octets pour intLastColumn
  • 9 octets pour chacune des 593 numeric(19,4)colonnes (5337 octets au total)
  • 1530 octets de surcharge de compression

Donc, 8 + 4 + (593 * 9) + 1530 = 6879. Attendez une seconde .... C'est toujours en dessous de 8060. Qu'est-ce qui se passe?!


L'algorithme de compression de page empile en fait plusieurs algorithmes de compression ensemble. La première étape consiste à appliquer la compression ROW. La surcharge de la compression de ligne n'est pas incluse dans les 1530 octets de surcharge répertoriés dans ce message d'erreur.

Vous pouvez en savoir plus sur le fonctionnement de la compression de lignes ici sur mon blog et ici dans BOL . Vous noterez dans l'article BOL qu'il décrit le numericstockage comme «Ce stockage est exactement le même que le format de stockage vardécimal», mais n'explique pas vardecimal. Ce message couvre vardecimalun peu plus - essentiellement, il ajoute 2 octets de surcharge par colonne pour stocker la longueur réelle (similaire à ce qui le varcharfait).

La compression des lignes nécessitera 2 octets supplémentaires pour chacune des 593 numericcolonnes, plus le bigintet intnécessitera 1 octet de surcharge chacun.

Les exigences de stockage compressées par ligne seraient les suivantes:

  • 8 octets + 1 octet de surcharge pour bigintMyTableID
  • 4 octets + 1 octet de surcharge pour intLastColumn
  • 9 octets + 2 octets de surcharge pour chacune des 593 numeric(19,4)colonnes
  • 1188 octets de surcharge de compression ROW

8 + 4 + (593 * 9) = 5349 octets de données

1 + 1 + (593 * 2) = surcharge de compression de ligne de 1188 octets

6537 octets au total pour le schéma compressé par ligne


Maintenant que nous avons la taille de ligne pour le schéma compressé par ligne, nous pouvons revoir nos calculs. La taille de la ligne compressée sera la taille des données + la surcharge de compression de ligne + la surcharge de compression de page:

  • 8 octets pour bigintMyTableID
  • 4 octets pour intLastColumn
  • 9 octets pour chacune des 593 numeric(19,4)colonnes
  • 1188 octets de surcharge de compression ROW
  • 1530 octets de surcharge de compression PAGE
  5349 octets de données 
+ 1188 octets de compression de ligne 
+ 1530 octets de compression de page 

8067 octets au total

AMtwo
la source
1
J'aime votre conclusion: "Dans la plupart des cas, vous constaterez que la compression des lignes est en mesure d'économiser de l'espace, mais pas toujours." 2718 octets de surcharge, c'est beaucoup plus que ce à quoi je m'attendais. Merci beaucoup d'avoir pris le temps d'écrire une réponse aussi détaillée.
Henrik Staun Poulsen
1
@HenrikStaunPoulsen Une autre chose importante à retenir est que SQL Server doit supposer que vos données pourraient ne pas être compressées. Ainsi, même si vos données sont compressées à moins de 8060 octets, SQL Server doit effectuer les calculs de taille de ligne en fonction de la taille de ligne maximale théorique pour les données non compressibles.
AMtwo
Après 3 jours, je suis toujours étonné du nombre d'octets requis pour la compression des lignes; 2 octets par colonne. La compression de page ajoute près de 3 octets en plus de cela. Mais; Merci de votre aide. C'était très utile.
Henrik Staun Poulsen