Kolumna tożsamości w indeksie magazynu kolumn

9

Mam bardzo dużą tabelę IMO (~ 137 milionów wierszy) z dużą ilością powtarzanych danych, dużą ilością NULLkolumn i tym podobne.

Rozważam zbadanie tego przy użyciu tabeli z COLUMNSTORE INDEXi mam IDENTITYkolumnę w oryginalnej tabeli, która jest moją jedyną kolumną, w której każdy wiersz jest unikalny.

Czy powinienem pominąć tę kolumnę, czy dołączyć ją? Przeczytałem, że chcesz uwzględnić wszystkie wiersze swojej tabeli, COLUMNSTORE INDEXale przeczytałem również, że najlepszymi kandydatami są kolumny z dużą ilością nieunikalnych wierszy.

Czy to tylko zły kandydat na COLUMNSTORE INDEX?

Korzystam z programu SQL Server 2012, więc jest to nieklastrowany magazyn kolumn. Właśnie badam możliwe lepsze sposoby przechowywania tych danych. Aktualizacje nie istnieją, chociaż nowe wiersze będą okresowo dodawane za pomocą procesu ELT, więc zakładam, że pewne prace zostałyby tam wykonane. Niektórzy ludzie wydobywają te dane i generują ogromne raporty, dużo skanowania wierszy, co czasami powoduje, że serwer jest indeksowany, co zmusza nas do codziennego odciążania kopii na serwerze pomocniczym.

Don
źródło
1
Czy kolumna tożsamości w oryginalnej tabeli jest również indeksem klastrowanym? Jeśli tak, SQL Server automatycznie uwzględni tę kolumnę w dowolnym nieklastrowanym indeksie magazynu kolumn, nawet jeśli nie zostaniesz o to wyraźnie poproszony. Jest to nieco podobne do sposobu, w jaki kolumny klastrowanego indeksu zostaną uwzględnione w nieklastrowanym indeksie b-drzewa, ale w tym przypadku dane będą przechowywane jako rzeczywiste skompresowane segmenty magazynu kolumn. Więcej informacji można znaleźć na stronie dba.stackexchange.com/questions/103722/ ...
Geoff Patterson
137 million rowsjest duży, ale łatwy do opanowania. Czy zastanawiałeś się nad podziałem tabeli i umieszczaniem jej w różnych aplikacjach? Indeks Columnsstore w SQL 2012 nie jest zapisywalny, więc będziesz miał problemy - musisz go upuścić i odtworzyć. Nie mówię, że wola magazynu kolumn jest zła, ale lepiej jest też zbadać inne opcje.
Kin Shah,

Odpowiedzi:

11

Kolumny tożsamości nie są tak naprawdę kompresowane w Indeksach magazynu kolumn w SQL Server 2012 lub SQL Server 2014. Wszystko to naprawdę będzie zależeć od obciążenia, którego doświadczasz. Jeśli twoje obciążenie obejmie kolumnę tożsamości, możesz bardzo pięknie skorzystać z eliminacji segmentów.

Z punktu widzenia kompresji - sklep Columnstore zapewni lepszą kompresję niż zwykle strona. Zazwyczaj Sprawdź to przed przejściem do produkcji.

Twoim największym problemem w SQL Server 2012 będzie bardzo słaba implementacja trybu wsadowego i nic nie możesz na to poradzić.

Niko Neugebuer
źródło
7
Witaj Niko !!!
Aaron Bertrand
3

Nie mogłem się oprzeć dołączeniu do Niko z inną odpowiedzią (witaj, Niko!). Ogólnie zgadzam się z Niko, że ograniczenia trybu wsadowego w SQL 2012 (jeśli Niko nie będzie łączył się z własnym blogiem, zrobię to :)) mogą być poważnym problemem. Ale jeśli możesz z nimi żyć i mieć pełną kontrolę nad każdym pisanym zapytaniem w stosunku do tabeli, aby dokładnie go zweryfikować, sklep z kolumnami może działać dla Ciebie w SQL 2012.

Jeśli chodzi o twoje szczegółowe pytania dotyczące kolumny tożsamości, stwierdziłem, że kolumna tożsamości bardzo dobrze się kompresuje i zdecydowanie zalecamy włączenie jej do indeksu magazynu kolumn przy każdym wstępnym testowaniu. (Zauważ, że jeśli kolumna tożsamości jest również indeksem klastrowym twojego b-drzewa, zostanie automatycznie uwzględniona w indeksie magazynu klastrów nieklastrowanych ).

Dla porównania, oto rozmiary, które zaobserwowałem dla ~ 10 MM wierszy danych w kolumnie tożsamości. Magazyn kolumn załadowany w celu optymalnej eliminacji segmentów kompresuje się do 26 MB (w porównaniu do 113 MB w przypadku PAGEkompresji tabeli magazynu wierszy), a nawet magazyn kolumn zbudowany na losowo uporządkowanym drzewie b ma tylko 40 MB. To pokazuje ogromną przewagę kompresji, nawet w porównaniu z najlepszą kompresją b-drzewa, którą SQL ma do zaoferowania, a nawet jeśli nie zadajesz sobie trudu, aby wyrównać dane w celu optymalnej eliminacji segmentów (co zrobiłbyś najpierw tworząc b-drzewa, a następnie budowanie magazynu kolumn za pomocą MAXDOP1).

wprowadź opis zdjęcia tutaj

Oto pełny skrypt, którego użyłem na wypadek, gdybyś chciał się pobawić:

-- 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
źródło
Dziękuję za wszystkie świetne odpowiedzi, teraz postanowiłem wstrzymać się, dopóki nie będę mógł dostać się na co najmniej SQL Server 2014. Zwiększamy nasze aktualizacje, więc mam nadzieję, że w przyszłym roku będziemy mogli to zrobić.
Don