web-dev-qa-db-fra.com

Utilisation de l'espace d'indice de colonne en cluster

J'ai une table simple avec un indice de colonne en cluster:

ID INT NOT NULL,
Hash BINARY(20) NOT NULL

Cette table compte quelque milliards de lignes et selon l'sp_spaceused, sys.allocation_units et SSMS rapporte que sa taille est d'environ 25 Go.

Mon problème est que je ne peux pas rendre compte de tout cet espace. Interrogation sys.column_store_row_groups et sys.column_store_segments ne me donne qu'environ 7,8 Go. L'index n'utilise aucun dictionnaire: primary_dictionary_id et secondary_dictionary_id sont -1 pour tous les segments. Interrogation sys.column_store_dictionaries ne renvoie pas de lignes du tout.

Le tuple déménageur a fait son travail et tous les groupes de lignes sont dans l'état comprimé. J'ai déjà essayé un ALTER INDEX REORGANIZE Au cas où.

Ma seule idée de la différence de taille est des éléments de type dictionnaire Je ne comptabilise pas. Des idées sur ce que je pourrais manquer?

Je cours SQL Server 2017 (RTM-CU4).


Edit 1 :

Ceci est la sortie de sp_spacaced pour la table en question:

+--------+------------+-------------+-------------+------------+----------+
|  name  |    rows    |  reserved   |    data     | index_size |  unused  |
+--------+------------+-------------+-------------+------------+----------+
| IdsBin | 1073741824 | 25028112 KB | 25007432 KB | 16 KB      | 20664 KB |
+--------+------------+-------------+-------------+------------+----------+

Edit 2 :

Ceci est un script de reproduction avec 1 million de lignes. Il court environ 1 minute sur ma machine. AVERTISSEMENT : Il choutes et recrée une nouvelle base de données

USE master;
GO
DROP DATABASE IF EXISTS MyDbWeirdTest;
GO
CREATE DATABASE MyDbWeirdTest;
GO
USE MyDbWeirdTest;
GO

CREATE TABLE IdsBin (
    ID INT NOT NULL,
    Hash BINARY(20) NOT NULL
);
CREATE CLUSTERED COLUMNSTORE INDEX ix1 ON IdsBin
GO

CREATE TYPE tBin AS TABLE (
    ID INT,
    Hash BINARY(20)
);
GO

CREATE OR ALTER PROCEDURE pBin (
    @ids AS dbo.tBin READONLY
)
AS
BEGIN
    SET NOCOUNT ON;

    INSERT dbo.IdsBin
    SELECT ID, Hash FROM @ids;
END;
GO

SET NOCOUNT ON;
DECLARE @i INT = 1, @t INT = 1;
DECLARE @tvp dbo.tBin;

WHILE @t <= 1000000
BEGIN
    DELETE @tvp;
    BEGIN TRAN;
    WHILE @i <= 1000
    BEGIN
        INSERT @tvp VALUES (@t, HASHBYTES('SHA1', CAST(@t AS BINARY(4))));
        SET @i = @i + 1;
        SET @t = @t + 1;
    END;

    EXEC pBin @tvp;
    COMMIT;
    SET @i = 1;
END;
GO

ALTER INDEX ix1 on IdsBin REBUILD;
GO

Pour ce reprovement, SP_SPACEUDED montre:

+--------+----------------------+----------+----------+------------+--------+
|  name  |         rows         | reserved |   data   | index_size | unused |
+--------+----------------------+----------+----------+------------+--------+
| IdsBin | 1000000              | 22728 KB | 22640 KB | 0 KB       | 88 KB  |
+--------+----------------------+----------+----------+------------+--------+

sys.Column_Store_row_groups:

+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+
| object_id | index_id | partition_number | row_group_id | delta_store_hobt_id | state | state_description | total_rows | deleted_rows | size_in_bytes |
+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+
| 901578250 |        1 |                1 |            0 | NULL                |     3 | COMPRESSED        |    1000000 |            0 |       5896938 |
+-----------+----------+------------------+--------------+---------------------+-------+-------------------+------------+--------------+---------------+

SO SP_SPACEUSUtilisé me donne environ 22 Mo et SYS.Allocation_units (non indiqués) accepte. Mais aucun ColuminStore DMVS semble être d'accord sur ce numéro et disent que l'indice est inférieur à 6 Mo de taille.

6
kirchner

sys.column_store_segments et sys.column_store_row_groups Store Quelques des informations de métadonnées sur les données de colonne, mais je crois que cela finit par représenter le compressé Taille. Il existe également des structures lobes qui sont également allouées et vous pouvez voir la taille non compressée dans l'unité d'allocation/la partition DMVS (et si vous arrivez aux pages d'une manière ou d'une autre avec DBCC PAGE, Je parie que vous verriez qu'ils sont relativement vides). En d'autres termes, sys.column_store_row_groups vous montre combien de données stockées sur ces pages, mais n'en ajoute pas dans l'espace libre sur ces pages (qui prennent toujours de la place dans le fichier de données et en mémoire, comme un index fragmenté ou un index avec un index fragmenté. facteur de remplissage).

J'ai couru votre repro et voici ce que j'ai vu:

SELECT 
  a.[type_desc], 
  p.[rows],
  a.total_pages, reserved_kb = a.total_pages * 8, 
  a.used_pages,  data_kb     = a.used_pages  * 8
FROM sys.allocation_units AS a
INNER JOIN sys.partitions AS p 
   ON a.container_id = p.[partition_id]
WHERE p.[object_id] = OBJECT_ID(N'dbo.IdsBin');

Résultats:

AU/partition query

Autre que inutilisé, que je n'ai pas pris la peine de calculer, les résultats correspondent à sp_spaceused:

sp_spaceused

Et vous pouvez confirmer ces chiffres dans sys.dm_db_partition_stats ainsi que:

SELECT 
  lob_reserved_page_count, reserved_kb = lob_reserved_page_count * 8,
  lob_used_page_count,     data_kb     = lob_used_page_count     * 8
FROM sys.dm_db_partition_stats 
WHERE [object_id] = OBJECT_ID(N'dbo.IdsBin');

Résultats:

dm_db_partition_stats

Vous avez mentionné cela mais je voulais juste appeler explicitement que sp_spaceused et allocation_units reflète le nombre de pages, peu importe la manière dont une page complète ou vide pourrait être. Les groupes de lignes DMV reflètent uniquement les données réelles. la documentation stipule (emphasis mine):

Taille en octets de tous Les données dans ce groupe de lignes (non compris les métadonnées ou les dictionnaires partagés)

Alors que sys.dm_db_partition_stats , par exemple, indique explicitement les pages tout au long, pas des données, même si je dirais qu'ils devraient spécifier que chaque LOB est une page de 8K ici:

Nombre total de lobes utilisés pour stocker et gérer l'indice de colonne dans la partition.

Quel numéro vous voulez faire confiance, eh bien, c'est à vous de décider.

En écart, Niko Neugebauer a parlé du fait que seule la taille comprimée des dictionnaires est exposée dans la colonne DMVS ici , et relevée A élément de rétroaction À ce sujet. Il me semble que d'autres informations pourraient également être exposées dans la colonne DMVS.

3
Aaron Bertrand