web-dev-qa-db-fra.com

Comment puis-je voir si les données d'une table SQL Server sont compressées en pages?

Ceci est une question complémentaire à une question que j'ai posée hier: Puis-je insérer en masse dans une table compressée par page vide et obtenir une compression complète? La réponse à cette question (paraphrasée de l'excellente réponse de Randi Vertongen ) est oui, mais cela nécessite que l'insert en vrac prenne un verrou au niveau de la table; sinon, l'insertion en bloc prend un verrou au niveau de la ligne et effectue uniquement la compression des données de la ligne. Cela soulève la question: comment savoir ensuite quelle compression est appliquée?

Voici les étapes pour créer des données compressées par ligne dans une table compressée théoriquement par page:
1. Créez une table avec DATA_COMPRESSION=PAGE et n'utilisez pas sp_tableoption pour activer l'option "verrouillage de la table lors d'un chargement en masse" pour cette table.
2. Utilisez bcp pour insérer en masse les données d'un fichier plat dans la nouvelle table, mais sans spécifier le -h TABLOCK option pour verrouiller la table.

Le résultat est une table dans laquelle les données sont compressées au niveau de la ligne (plus petite qu'une table non compressée mais plus grande qu'une table compressée par page), mais en inspectant le sys.allocation_units le tableau du catalogue montre la compression des données sous forme de page.

La question

Lorsque la table allocation de données est destinée à la compression de page comme dans ce scénario, que puis-je faire pour savoir si la données de cette table est compressée?

7
Caitlin M. Shaw

Pour voir si les pages de données sont effectivement "PAGE" compressées ou non, vous pouvez utiliser la fonction DMF non documentée sys.dm_db_database_page_allocations(). Le is_page_compressed Le champ contient les informations que vous recherchez. Vous devrez utiliser le mode DETAILED (c'est-à-dire le 5ème paramètre), sinon les valeurs de ce champ seront toutes NULL.

Pour être clair (sur la base du libellé de la question, "que puis-je faire pour savoir si le données dans ce tableau est compressé par page?"), Ce n'est pas un tout ou- aucun problème: la compression de page est appliquée pour chaque page de données, donc vous ne pouvez en avoir aucun qui soit compressé, en cours de compression ou toute combinaison entre les deux. Donc, vous devez regarder toutes les pages. Et non, vous ne pouvez pas nécessairement supposer qu'une seule page compressée non-page indique que vous devez REBUILD car une page non remplie ne se compressera pas.

Par exemple:

SELECT [is_page_compressed]
FROM   sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID(N'dbo.CompressedHeap'),
                                           0, 1, 'DETAILED');

Ce qui suit montre que les pages de données ne sont pas initialement compressées, mais qu'elles le sont après l'opération REBUILD:

USE [tempdb];

-- DROP TABLE dbo.CompressedHeap;
CREATE TABLE dbo.CompressedHeap
(
  ID INT IDENTITY(1, 1) NOT NULL,
  String sysname,
  [MaxLength] SMALLINT,
  [Type] VARCHAR(5)
) WITH (DATA_COMPRESSION = PAGE);


INSERT INTO dbo.CompressedHeap ([String], [MaxLength], [Type])
  SELECT col.[name], col.[max_length], obj.[type]
  FROM   master.sys.columns col
  CROSS JOIN master.sys.objects obj;


SELECT [is_page_compressed], *
FROM   sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID(N'dbo.CompressedHeap'),
                                           0, 1, 'DETAILED')
WHERE  [is_iam_page] = 0
AND    [is_allocated] = 1;
-- 394 pages


ALTER TABLE dbo.CompressedHeap REBUILD;


SELECT [is_page_compressed], *
FROM   sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID(N'dbo.CompressedHeap'),
                                           0, 1, 'DETAILED')
WHERE  [is_iam_page] = 0
AND    [is_allocated] = 1;
-- 179 pages
13
Solomon Rutzky

Vous pouvez trouver le niveau de compression dans sys.partitions dmv

SELECT t.name AS tablename,
       i.name AS indexname,
       p.data_compression_desc
FROM sys.tables AS t
INNER JOIN sys.indexes AS i
     ON t.object_id = i.object_id
INNER JOIN sys.partitions AS p
     ON i.object_id = p.object_id
        AND i.index_id = p.index_id;
0
Bob Klimes