Colonne d'identité dans l'index columnstore


9

J'ai une table IMO extrêmement grande (~ 137 millions de lignes) avec beaucoup de données répétées, beaucoup de NULLcolonnes, etc.

J'envisage d'explorer cela en utilisant un tableau avec un COLUMNSTORE INDEXet j'ai une IDENTITYcolonne dans le tableau d'origine, qui est ma seule colonne où chaque ligne est unique.

Dois-je laisser cette colonne ou l'inclure? J'ai lu que vous souhaitez inclure toutes les lignes de votre tableau dans le COLUMNSTORE INDEXmais j'ai également lu que les meilleurs candidats sont des colonnes avec beaucoup de lignes non uniques.

Est-ce juste un mauvais candidat pour un COLUMNSTORE INDEX?

J'utilise SQL Server 2012, il s'agit donc d'un magasin de colonnes non cluster. J'explore simplement de meilleures façons possibles de stocker ces données. Les mises à jour sont inexistantes, bien que de nouvelles lignes soient périodiquement ajoutées via un processus ELT, donc je suppose que du travail y sera effectué. Certaines personnes exploitent ces données et génèrent d'énormes rapports, de nombreuses analyses des lignes, entraînent parfois le serveur à une analyse qui nous a obligés à décharger une copie quotidiennement sur un serveur secondaire.


1
La colonne d'identité de la table d'origine est-elle également votre index cluster? Si tel est le cas, SQL Server inclura automatiquement cette colonne dans tout index columnstore non clusterisé, même si vous ne le demandez pas explicitement. Ceci est quelque peu similaire à la façon dont les colonnes d'index cluster seront incluses dans un index b-tree non cluster, mais les données seront stockées en tant que segments de magasin de colonnes compressés réels dans ce cas. Voir dba.stackexchange.com/questions/103722/… pour plus d'informations.
Geoff Patterson

137 million rowsest grand mais gérable. Avez-vous envisagé de partitionner la table et de la placer dans différents groupes de fichiers? L'index Columnsstore dans SQL 2012 n'est pas accessible en écriture, vous allez donc rencontrer des problèmes - vous devez le supprimer et le recréer. Je ne dis pas que la volonté de columnstore est mauvaise, mais il vaut mieux explorer d'autres options également.
Kin Shah

Réponses:


11

Les colonnes d'identité ne sont pas vraiment compressées dans les index Columnstore dans SQL Server 2012 ou SQL Server 2014. Tout dépendra vraiment de la charge de travail que vous rencontrez. Si votre charge de travail comprend la colonne d'identité, vous pouvez très bien profiter de l' élimination du segment.

Du point de vue de la compression - Columnstore vous fournira une meilleure compression que la page ne le fait généralement. Typiquement. Veuillez le tester avant de passer à la production.

Votre plus gros problème dans SQL Server 2012 sera une implémentation très faible du mode batch, et vous ne pouvez rien y faire.


7
Bienvenue Niko !!!
Aaron Bertrand

3

Je n'ai pas pu résister à rejoindre Niko avec une autre réponse (bienvenue, Niko!). En général, je suis d'accord avec Niko que les limitations du mode batch dans SQL 2012 (si Niko ne crée pas de lien vers son propre blog, je le ferai :)) peuvent être une préoccupation majeure. Mais si vous pouvez vivre avec ceux-ci et avoir un contrôle total sur chaque requête que vous écrivez sur la table pour l'examiner attentivement, columnstore pourrait fonctionner pour vous dans SQL 2012.

En ce qui concerne vos questions spécifiques sur la colonne d'identité, j'ai trouvé que la colonne d'identité se comprime très bien et je recommande fortement de l'inclure dans votre index columnstore lors de tout test initial. (Notez que si la colonne d'identité se trouve être également l'index cluster de votre b-tree, elle sera automatiquement incluse dans votre index columnstore non cluster .)

Pour référence, voici les tailles que j'ai observées pour ~ 10 MM de lignes de données de colonne d'identité. Le magasin de colonnes chargé pour une élimination optimale des segments se comprime à 26 Mo (contre 113 Mo pour la PAGEcompression de la table de magasin de lignes), et même le magasin de colonnes construit sur un arbre b ordonné de façon aléatoire ne fait que 40 Mo. Cela montre donc un énorme avantage de compression, même par rapport à la meilleure compression SQL que b-tree peut offrir et même si vous ne prenez pas la peine d'aligner vos données pour une élimination optimale des segments (ce que vous feriez en créant d'abord un b-tree puis construire votre magasin de colonnes avec MAXDOP1).

entrez la description de l'image ici

Voici le script complet que j'ai utilisé au cas où vous voudriez jouer:

-- Confirm SQL version
SELECT @@version
--Microsoft SQL Server 2012 - 11.0.5613.0 (X64) 
--  May  4 2015 19:05:02 
--  Copyright (c) Microsoft Corporation
--  Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: )


-- Create a columnstore table with identity column that is the primary key
-- This will yield 10 columnstore segments @ 1048576 rows each
SELECT i = IDENTITY(int, 1, 1), ROW_NUMBER() OVER (ORDER BY randGuid) as randCol
INTO #testIdentityCompression_sortedColumnstore
FROM (
    SELECT TOP 10485760 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS randI, NEWID() AS randGuid
    FROM master..spt_values v1
    CROSS JOIN master..spt_values v2
    CROSS JOIN master..spt_values v3
) r
ORDER BY r.randI
GO
ALTER TABLE #testIdentityCompression_sortedColumnstore
ADD PRIMARY KEY (i)
GO
-- Load using a pre-ordered b-tree and one thread for optimal segment elimination
-- See http://www.nikoport.com/2014/04/16/clustered-columnstore-indexes-part-29-data-loading-for-better-segment-elimination/
CREATE NONCLUSTERED COLUMNSTORE INDEX cs_#testIdentityCompression_sortedColumnstore ON #testIdentityCompression_sortedColumnstore (i) WITH (MAXDOP = 1)
GO

-- Create another table with the same data, but randomly ordered
SELECT *
INTO #testIdentityCompression_randomOrderColumnstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_randomOrderColumnstore
ADD UNIQUE CLUSTERED (randCol)
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX cs_#testIdentityCompression_randomOrderColumnstore ON #testIdentityCompression_randomOrderColumnstore (i) WITH (MAXDOP = 1)
GO

-- Create a b-tree with the identity column data and no compression
-- Note that we copy over only the identity column since we'll be looking at the total size of the b-tree index
-- If anything, this gives an unfair "advantage" to the rowstore-page-compressed version since more
-- rows fit on a page and page compression rates should be better without the "randCol" column.
SELECT i
INTO #testIdentityCompression_uncompressedRowstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_uncompressedRowstore
ADD PRIMARY KEY (i)
GO

-- Create a b-tree with the identity column and page compression
SELECT i
INTO #testIdentityCompression_compressedRowstore
FROM #testIdentityCompression_sortedColumnstore
GO
ALTER TABLE #testIdentityCompression_compressedRowstore
ADD PRIMARY KEY (i)
WITH (DATA_COMPRESSION = PAGE)
GO

-- Compare all the sizes!
SELECT OBJECT_NAME(p.object_id, 2) AS tableName, COUNT(*) AS num_segments, SUM(on_disk_size / (1024.*1024.)) as size_mb
FROM tempdb.sys.partitions p
JOIN tempdb.sys.column_store_segments s
    ON s.partition_id = p.partition_id
    AND s.column_id = 1
WHERE p.object_id IN (OBJECT_ID('tempdb..#testIdentityCompression_sortedColumnstore'),OBJECT_ID('tempdb..#testIdentityCompression_randomOrderColumnstore'))
GROUP BY p.object_id
UNION ALL
SELECT OBJECT_NAME(p.object_id, 2) AS tableName
    , NULL AS num_segments
    , (a.total_pages*8.0) / (1024.0) as size_mb
FROM tempdb.sys.partitions p
JOIN tempdb.sys.allocation_units a
    ON a.container_id = p.partition_id
WHERE p.object_id IN (OBJECT_ID('tempdb..#testIdentityCompression_compressedRowstore'),OBJECT_ID('tempdb..#testIdentityCompression_uncompressedRowstore'))
ORDER BY 3 ASC
GO

Merci pour toutes les bonnes réponses, en ce moment, j'ai décidé de ne pas attendre jusqu'à ce que je puisse obtenir au moins le serveur SQL 2014. Nous intensifions nos mises à niveau, donc j'espère que l'année prochaine ou nous pourrons le faire.
Don
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.