web-dev-qa-db-fra.com

Puis-je insérer en masse dans une table compressée par page vide et obtenir une compression complète?

J'ai beaucoup de grandes tables (environ 10 millions de lignes larges) qui doivent être régulièrement chargées dans SQL Server 2016 pour des rapports en lecture seule. Je voudrais que ces tables soient aussi petites que possible sur le disque, et cela compte plus que les améliorations de performances dans le chargement ou l'interrogation.

Voici ce que j'ai fait pour les tables qui ne nécessitent plus d'indexation:

  1. Créez le tableau avec DATA_COMPRESSION=PAGE.
  2. Utilisez bcp pour insérer en masse les données d'un fichier plat dans la nouvelle table.

Les types de colonnes dans les tables sont varchar (jamais plus de 512, pas max), float, tinyint ou date (pas datetime). Toutes les colonnes sont créées comme nullables et aucune clé primaire ou étrangère n'est définie - elles n'ont pas d'importance pour l'interrogation et les tables ne sont jamais mises à jour directement. Le classement par défaut sur tout est SQL_Latin1_General_CP1_CI_AS.

Lorsque je fais cela, je peux voir dans sys.allocation_units cette compression de données de page a été appliquée au tas et je peux voir dans sys.partitions que le facteur de remplissage est correctement 0 (100%). Étant donné que les tables sont beaucoup plus petites que les tables non compressées, je pensais que la compression était terminée.

Cependant, si je reconstruis ensuite avec la même option DATA_COMPRESSION=PAGE, la table soi-disant déjà compressée devient environ 30% plus petite! Il semble que cela passe d'environ 17 lignes par page de données à 25 lignes par page. (Une seule fois, cependant. La reconstruction à nouveau après cela ne la rend pas plus petite que la première reconstruction.)

Les questions

Mes questions sont donc les suivantes: a) que se passe-t-il ici? et (b) existe-t-il un moyen d'obtenir cette taille compressée extra-petite directement lorsque je charge la table sans avoir à reconstruire après le chargement des données?

7
Caitlin M. Shaw

@ HandyD est tout à fait correct, je veux seulement mettre en évidence d'autres méthodes pour obtenir la compression lors de l'insertion dans un tas.

Du même document

Lorsqu'un segment est configuré pour la compression au niveau de la page, les pages ne reçoivent la compression au niveau de la page que des manières suivantes:

  • Les données sont importées en masse avec des optimisations en masse activées.
  • Les données sont insérées à l'aide de la syntaxe INSERT INTO ... WITH (TABLOCK) et la table n'a pas d'index non cluster.
  • Une table est reconstruite en exécutant l'instruction ALTER TABLE ... REBUILD avec l'option de compression PAGE.

En fonction de cela, vous pouvez tirer parti des insertions en bloc à journalisation minimale ou utiliser INSERT INTO ... WITH (TABLOCK) pour obtenir la compression PAGE sans avoir à effectuer de reconstructions.


a) que se passe-t-il ici? et (b) existe-t-il un moyen d'obtenir cette taille compressée extra-petite directement lorsque je charge la table sans avoir à reconstruire après le chargement des données?

Il existe des règles pour obtenir la compression PAGE lors de l'insertion dans un segment de mémoire, ajoutez -h "TABLOCK" à votre commande bcp pour obtenir la compression.

ROW la compression fonctionne sans ces prérequis et est la moindre quantité de compression utilisée dans les exemples ci-dessous, merci @ DenisRubashkin pour l'avoir signalé!


Essai

Exemple de commande de démarrage de données et de sortie BCP


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

La taille ROW compressée et non compressée

La taille des données est à 132272 KB lors d'une insertion standard dans le tas, c'est ROW compressé mais pas PAGE compressé.

La taille des données sans aucune compression est ~ 176216 KB pour notre 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

INSÉRER DANS ... AVEC TABLOCK

Insertion de WITH TABLOCK nous donne la taille des données compressées PAGE, 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

INSERT EN VRAC

Maintenant, lorsque nous créons une table de tas de destination qui est également page compressée, et faisons une insertion en bloc 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)

Les données sont page compressées et se trouvent également à 69480 KB:

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

BCP AVEC TABLOCK

Vous pouvez obtenir les mêmes résultats que le BULK INSERT WITH TABLOCK en utilisant BCP IN avec le -h "TABLOCK" indice. Cela a du sens, ils font la même chose en interne

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

La taille résultante étant 69480 KB

BCP IN SANS TABLOCK

Utilisation de BCP pour charger des données à partir du même fichier dans une copie de la table de destination

Et une commande bcp standard se traduit par des données non compressées:

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

Avec la taille des données à 132272 KB (ligne compressée).

8
Randi Vertongen

Selon l'article Docs sur la compression:

Les nouvelles pages allouées dans un segment de mémoire dans le cadre des opérations DML n'utilisent pas la compression de PAGE tant que le segment de mémoire n'est pas reconstruit. Reconstruisez le tas en supprimant et en réappliquant la compression, ou en créant et supprimant un index cluster.

Cela semble correspondre à ce que vous voyez. Il semble que vous n'obteniez pas de compression sur la table avant de la reconstruire. Vous pouvez essayer de charger les données sur une table non compressée et voir si vous avez toujours une moyenne de 17 lignes par page ou si cela diminue. S'il reste le même, alors vous n'obtenez pas de compression et la reconstruction est nécessaire.

Vous pouvez également ajouter un index cluster à votre table et cela devrait empêcher votre table d'être décompressée/faiblement compressée après le chargement en bloc de vos données.

5
HandyD