Identitätsspalte im Columnstore-Index

9

Ich habe eine extrem große IMO-Tabelle (~ 137 Millionen Zeilen) mit vielen wiederholten Daten, vielen NULLSpalten und dergleichen.

Ich denke darüber nach, dies anhand einer Tabelle mit a zu untersuchen, COLUMNSTORE INDEXund ich habe eine IDENTITYSpalte in der Originaltabelle, die meine einzige Spalte ist, in der jede Zeile eindeutig ist.

Soll ich diese Spalte weglassen oder einfügen? Ich habe gelesen, dass Sie alle Zeilen Ihrer Tabelle in die COLUMNSTORE INDEXListe aufnehmen möchten, aber ich habe auch gelesen, dass die besten Kandidaten Spalten mit vielen nicht eindeutigen Zeilen sind.

Ist das nur ein schlechter Kandidat für eine COLUMNSTORE INDEX?

Ich verwende SQL Server 2012, es handelt sich also um einen nicht gruppierten Spaltenspeicher. Ich erkunde nur mögliche bessere Möglichkeiten zum Speichern dieser Daten. Aktualisierungen sind nicht vorhanden, obwohl regelmäßig neue Zeilen durch einen ELT-Prozess hinzugefügt werden, sodass ich davon ausgehe, dass dort einige Arbeiten durchgeführt werden. Einige Leute nutzen diese Daten und generieren riesige Berichte, viele Scans von Zeilen, die den Server manchmal zum Crawlen bringen, was uns gezwungen hat, täglich eine Kopie auf einen sekundären Server zu verlagern.

Don
quelle
1
Ist die Identitätsspalte in der Originaltabelle auch Ihr Clustered-Index? In diesem Fall nimmt SQL Server diese Spalte automatisch in einen nicht gruppierten Spaltenspeicherindex auf, auch wenn Sie nicht explizit danach fragen. Dies ähnelt in gewisser Weise der Art und Weise, wie Clustered-Indexspalten in einem nicht-Clustered-B-Tree-Index enthalten sind. In diesem Fall werden die Daten jedoch als tatsächliche komprimierte Columnstore-Segmente gespeichert. Weitere Informationen finden Sie unter dba.stackexchange.com/questions/103722/… .
Geoff Patterson
137 million rowsist groß aber überschaubar. Haben Sie sich mit der Partitionierung der Tabelle und der Zuordnung zu verschiedenen Dateigruppen befasst? Der Columnsstore-Index in SQL 2012 ist nicht beschreibbar, daher treten Probleme auf. Sie müssen ihn löschen und neu erstellen. Ich sage nicht, dass der Wille des Columnstores schlecht ist, aber es ist besser, auch andere Optionen zu erkunden.
Kin Shah

Antworten:

11

Identitätsspalten werden in Columnstore-Indizes in SQL Server 2012 oder in SQL Server 2014 nicht wirklich komprimiert. Dies hängt wirklich von der Arbeitslast ab, die Sie erleben. Wenn Ihre Arbeitslast die Identitätsspalte enthält, können Sie die Segmenteliminierung sehr gut nutzen .

Unter dem Gesichtspunkt der Komprimierung bietet Columnstore eine bessere Komprimierung als die Seite normalerweise. Typischerweise. Bitte testen Sie es, bevor Sie mit der Produktion beginnen.

Ihr größtes Problem in SQL Server 2012 wird eine sehr schwache Implementierung des Stapelmodus sein, und Sie können nichts dagegen tun.

Niko Neugebuer
quelle
7
Willkommen Niko !!!
Aaron Bertrand
3

Ich konnte nicht widerstehen, mich Niko mit einer anderen Antwort anzuschließen (willkommen, Niko!). Im Allgemeinen stimme ich Niko zu, dass die Einschränkungen des Batch-Modus in SQL 2012 (wenn Niko keinen Link zu seinem eigenen Blog erstellt, werde ich :)) ein großes Problem darstellen können. Wenn Sie jedoch mit diesen leben können und die volle Kontrolle über jede Abfrage haben, die Sie für die Tabelle schreiben, um sie sorgfältig zu überprüfen, könnte der Spaltenspeicher in SQL 2012 für Sie funktionieren.

In Bezug auf Ihre spezifischen Fragen zur Identitätsspalte stellte ich fest, dass die Identitätsspalte sehr gut komprimiert ist, und würde dringend empfehlen, sie in Ihren Columnstore-Index aufzunehmen, wenn Sie erste Tests durchführen. (Beachten Sie, dass die Identitätsspalte, wenn sie zufällig auch der Clustered-Index Ihres B-Tree ist, automatisch in Ihren nicht-Clustered Columnstore-Index aufgenommen wird .)

Als Referenz sind hier die Größen aufgeführt, die ich für ~ 10 MM Zeilen mit Identitätsspaltendaten beobachtet habe. Der für eine optimale Segmenteliminierung geladene Spaltenspeicher wird auf 26 MB PAGEkomprimiert (gegenüber 113 MB für die Komprimierung der Zeilenspeichertabelle), und selbst der auf einem zufällig angeordneten B-Baum aufgebaute Spaltenspeicher ist nur 40 MB groß. Dies zeigt also einen enormen Komprimierungsvorteil, selbst gegenüber der besten B-Tree-Komprimierung, die SQL zu bieten hat, und selbst wenn Sie sich nicht die Mühe machen, Ihre Daten für eine optimale Segmenteliminierung auszurichten (was Sie tun würden, indem Sie zuerst einen B-Tree erstellen und dann Erstellen Sie Ihren Columnstore mit MAXDOP1).

Geben Sie hier die Bildbeschreibung ein

Hier ist das vollständige Skript, das ich für den Fall verwendet habe, dass Sie herumspielen möchten:

-- 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
quelle
Vielen Dank für all die tollen Antworten. Im Moment habe ich mich entschlossen, mich zurückzuhalten, bis ich mindestens auf den SQL Server 2014 zugreifen kann. Wir verstärken unsere Upgrades, also hoffe ich, dass wir dies im nächsten Jahr tun können.
Don