Code zum Erstellen eines Clustered Columnstore-Index unter Beibehaltung der Zeilenreihenfolge

8

Ich möchte eine Rowstore-Tabelle in eine Columnstore-Tabelle konvertieren, indem ich einen Clustered Columnstore-Index erstelle. Die Tabelle enthält drei Spalten: ID, Zeit und Wert.

Die Tabelle wird nach ID und Uhrzeit sortiert, bevor ein Spaltenspeicherindex erstellt wird. Nach dem Erstellen des Columnstore-Index wird die Zeilenreihenfolge jedoch durcheinander gebracht. Ich dachte, es könnte an der Parallelität liegen und fügte die maxdop = 1Option hinzu , aber das hat das Problem nicht behoben. Kann mir jemand dabei helfen?

Hier ist der Code zum Erstellen von Tabellen und Indizes:

-- creating rowstore table
drop table if exists tab1_rstore
select id, time, value
into tab1_rstore
from tab0
order by id_loan, period
option(maxdop 1)

-- creating clustered index on rowstore table
create clustered index idx on tab1_rstore (id,time)

-- creating columnstore table 
select * 
into tab1_cstore
from tab1_rstore
    option(maxdop 1)

-- comparing the first two rows from these two tables
    select top 2 *
from tab1_rstore

    select top 2 *
from tab1_cstore

Der Screenshot der Abfrageergebnisse:

Die ersten beiden Zeilen vor dem C-Index

-- creating clustered columnstore index
create clustered columnstore index idx on tab1_cstore 
with (maxdop = 1) 

-- comparing the top two rows again
select top 2 *
from tab1_rstore

select top 2 *
from tab1_cstore

Der Screenshot der Abfrageergebnisse mit Columnstore-Index:

Geben Sie hier die Bildbeschreibung ein

Mein Verständnis ist, dass die Reihenfolge der Zeilen durch den Komprimierungsalgorithmus bestimmt wird und wir nichts dagegen tun können. Siehe die Einschränkung und Einschränkung im Dokument hier mit dem folgenden Zitat:

Die ASC- oder DESC-Schlüsselwörter zum Sortieren des Index können nicht enthalten sein. Columnstore-Indizes werden gemäß den Komprimierungsalgorithmen geordnet. Durch das Sortieren würden viele der Leistungsvorteile beseitigt.

Ich verwende SQL Server 2016 Developer Edition unter Windows 10 64-Bit.

Jason
quelle

Antworten:

14

Ein Clustered Columnstore-Index unterscheidet sich grundlegend von einem Clustered Rowstore-Index. Möglicherweise haben Sie bemerkt, dass es keine Schlüsselspaltenspezifikation für einen Clustered Columnstore-Index gibt. Das ist richtig: Ein Clustered Columnstore-Index ist ein Index ohne Schlüssel - alle Spalten sind "enthalten".

Die intuitivste Beschreibung, die ich für einen Clustered Columnstore-Index gehört habe, ist, ihn als spaltenorientierte Heap- Tabelle zu betrachten (wo sich die 'RID' befindet rowgroup_id, row_number).

Wenn Sie Indizes benötigen, um die direkte Reihenfolge und / oder die Auswahl von Punkten / kleinen Bereichen zu unterstützen, können Sie in SQL Server 2016 über dem Clustered Columnstore aktualisierbare Rowstore-B-Tree-Indizes erstellen.

In vielen Fällen ist dies einfach nicht erforderlich , da der Zugriff auf den Spaltenspeicher und die Sortierung im Stapelmodus so schnell sind. Viele der Dinge, die die Leute über die Leistung von Rowstores "wissen", müssen für Columnstore neu gelernt werden. Scans und Hashes sind gut :)

Allerdings hat der Spaltenspeicher natürlich eine Struktur für seine Zeilengruppen (und Metadaten zu Min / Max-Werten in jedem Segment), die bei Abfragen hilfreich sein kann, die von der Eliminierung von Zeilengruppen / Segmenten profitieren können.

Eine wichtige Technik in diesem Bereich besteht darin, zuerst einen Clustered Rowstore-Index mit der gewünschten Reihenfolge zu erstellen und dann mit der WITH (DROP_EXISTING = ON, MAXDOP = 1)Option den Clustered Columnstore-Index zu erstellen . In Ihrem Beispiel:

CREATE [UNIQUE] CLUSTERED INDEX idx 
ON dbo.tab1_cstore (id, time)
WITH (MAXDOP = 1);

CREATE CLUSTERED COLUMNSTORE INDEX idx 
ON dbo.tab1_cstore
WITH (DROP_EXISTING = ON, MAXDOP = 1);

Es ist Vorsicht geboten, um die Vorteile der Eliminierung von Zeilengruppen / Segmenten über einen längeren Zeitraum hinweg aufrechtzuerhalten. Auch wenn der Spaltenspeicher bereits implizit nach Zeilengruppen partitioniert ist, können Sie ihn auch explizit partitionieren.

Ich bin nicht 100% sicher, was Sie testen möchten, aber es ist wahr, dass die 'Reihenfolge' der Werte innerhalb eines Segments durch den Komprimierungsalgorithmus bestimmt wird. Mein Punkt beim Erstellen des Columnstore-Index mit DROP_EXISTINGist die Reihenfolge der Daten, die in den Segmenterstellungsprozess fließen, damit die Segmente insgesamt auf eine bestimmte Weise geordnet werden. Innerhalb des Segments sind alle Wetten ungültig.

Paul White 9
quelle
2

Abgesehen davon glaube ich, dass das SQL Server Tiger-Team sich der Notwendigkeit einer ORDER BYKlausel oder einer ähnlichen Klausel für die Erstellung von Columnstore-Indizes bewusst ist , um die Möglichkeit zur Eliminierung von Zeilengruppen zu maximieren.

Außerdem ist es zu diesem Zeitpunkt sehr wichtig sicherzustellen , dass Sie , wie in einer anderen Antwort hier, MAXDOP = 1beim Erstellen des Columnstore-Index verwenden. Wenn Sie dies nicht tun, werden die Daten in mehrere Threads aufgeteilt, wodurch die Möglichkeit einer möglichst effizienten Eliminierung von Zeilengruppen erheblich reduziert wird.

SQLArchitect
quelle