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 PAGE
compression 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 MAXDOP
1).
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