Coluna de identidade no índice columnstore

9

Eu tenho uma IMO de tabela extremamente grande (~ 137 milhões de linhas) com muitos dados repetidos, muitas NULLcolunas e assim por diante .

Estou pensando em explorar isso usando uma tabela com COLUMNSTORE INDEXae tenho uma IDENTITYcoluna na tabela original, que é minha única coluna em que cada linha é única.

Devo deixar esta coluna de fora ou incluí-la? Li que você deseja incluir todas as linhas da sua tabela no, COLUMNSTORE INDEXmas também li que os melhores candidatos são colunas com muitas linhas não exclusivas.

Este é apenas um candidato ruim para um COLUMNSTORE INDEX?

Estou usando o SQL Server 2012, por isso é um columnstore não clusterizado. Estou apenas explorando possíveis maneiras melhores de armazenar esses dados. As atualizações são inexistentes, embora novas linhas sejam adicionadas periodicamente por meio de um processo ELT, portanto, estou assumindo que algum trabalho seria feito lá. Algumas pessoas extraem esses dados e geram relatórios enormes, muitas varreduras de linhas, levando o servidor a rastrear às vezes, o que nos forçou a descarregar uma cópia diariamente para um servidor secundário.

Don
fonte
11
A coluna de identidade na tabela original também é seu índice em cluster? Nesse caso, o SQL Server incluirá automaticamente essa coluna em qualquer índice columnstore não agrupado em cluster, mesmo que você não solicite explicitamente. Isso é um pouco semelhante à maneira como as colunas de índice agrupadas serão incluídas em um índice b-tree não agrupado, mas os dados serão armazenados como segmentos reais de columnstore compactados nesse caso. Consulte dba.stackexchange.com/questions/103722/… para obter mais informações.
Geoff Patterson
137 million rowsé grande, mas gerenciável. Você já pensou em particionar a tabela e colocá-la em diferentes grupos de arquivos? O índice Columnsstore no sql 2012 não pode ser gravado, portanto você terá problemas - é necessário eliminá-lo e recriá-lo. Não estou dizendo que o columnstore será ruim, mas é melhor explorar outras opções também.
Kin Shah

Respostas:

11

As colunas de identidade não são realmente compactadas nos índices Columnstore no SQL Server 2012 ou no SQL Server 2014. Tudo depende verdadeiramente da carga de trabalho que você está enfrentando. Se sua carga de trabalho incluir a coluna de identidade, você poderá aproveitar muito bem a eliminação do segmento.

Do ponto de vista da compactação - o Columnstore fornecerá uma compactação melhor do que a página normalmente oferece. Tipicamente. Teste-o antes de avançar para a produção.

Seu maior problema no SQL Server 2012 será uma implementação muito fraca do Modo de Lote, e não há nada que você possa fazer sobre isso.

Niko Neugebuer
fonte
7
Bem-vindo Niko !!!
Aaron Bertrand
3

Não pude resistir em juntar-me ao Niko com outra resposta (bem-vindo, Niko!). Em geral, concordo com Niko que as limitações do modo de lote no SQL 2012 (se o Niko não criar um link para seu próprio blog, eu irei :)) podem ser uma grande preocupação. Mas se você pode conviver com eles e ter controle total sobre todas as consultas que está escrevendo na tabela para examiná-las cuidadosamente, o columnstore pode funcionar para você no SQL 2012.

No que diz respeito às suas perguntas específicas sobre a coluna de identidade, descobri que a coluna de identidade é muito compacta e recomendo incluí-la no seu índice columnstore em qualquer teste inicial. (Observe que se a coluna de identidade também for o índice em cluster da sua árvore b, ela será automaticamente incluída no índice columnstore não em cluster ).

Para referência, aqui estão os tamanhos que observei para ~ 10MM linhas de dados da coluna de identidade. O columnstore carregado para a eliminação ideal do segmento é compactado em 26 MB (vs. 113 MB para PAGEcompactação da tabela rowstore), e até o columnstore construído em uma b-tree ordenada aleatoriamente tem apenas 40 MB. Portanto, isso mostra um enorme benefício de compactação, mesmo com a melhor compactação de árvore b que o SQL tem a oferecer e mesmo que você não se preocupe em alinhar seus dados para a eliminação ideal do segmento (o que você faria primeiro criando uma árvore b e depois construindo seu columnstore com MAXDOP1).

insira a descrição da imagem aqui

Aqui está o script completo que eu usei, caso você queira brincar:

-- 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
Geoff Patterson
fonte
Obrigado por todas as ótimas respostas, no momento eu decidi adiar até que eu possa acessar pelo menos o servidor sql 2014. estamos intensificando nossas atualizações, então espero que no próximo ano ou assim possamos fazer isso.
Don