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:
DATA_COMPRESSION=PAGE
.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?
@ 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é!
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).
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.