Zum Inhalt springen

Tipps zu Parquet

Im Folgenden eine Sammlung von Tipps für den Umgang mit Parquet-Dateien.

Tipps zum Lesen von Parquet-Dateien

union_by_name verwenden, wenn Dateien unterschiedliche Schemas haben

Die Option union_by_name vereinheitlicht das Schema von Dateien, die unterschiedliche oder fehlende Spalten haben. Für Dateien, denen bestimmte Spalten fehlen, werden NULL-Werte eingesetzt:

SELECT *
FROM read_parquet('flights*.parquet', union_by_name = true);

Tipps zum Schreiben von Parquet-Dateien

Ein Glob-Muster beim Lesen oder eine Hive-Partitionierungsstruktur sind gute Wege, mehrere Dateien transparent zu behandeln.

PER_THREAD_OUTPUT aktivieren

Wenn die endgültige Anzahl der Parquet-Dateien nicht wichtig ist, kann das Schreiben einer Datei pro Thread die Leistung deutlich verbessern:

COPY
(FROM generate_series(10_000_000))
TO 'test.parquet'
(FORMAT parquet, PER_THREAD_OUTPUT);

Eine ROW_GROUP_SIZE wählen

Der Parameter ROW_GROUP_SIZE legt die Mindestanzahl von Zeilen in einer Parquet-Row-Group fest, mit einem Mindestwert gleich der Vektorgröße von DuckDB, 2.048, und einem Standard von 122.880. Eine Parquet-Row-Group ist eine Partition von Zeilen und besteht aus einem Column Chunk für jede Spalte im Datensatz.

Kompressionsalgorithmen greifen nur pro Row Group. Je größer die Row Group, desto mehr Möglichkeiten zur Datenkompression. Andererseits bedeuten größere Row Groups, dass jeder Thread beim Streamen der Ergebnisse mehr Daten im Speicher hält, bevor er sie schreibt. Ein Argument für kleinere Row Groups ist, dass DuckDB Parquet-Row-Groups auch innerhalb derselben Datei parallel lesen kann und Predicate-Pushdown nutzt, um nur die Row Groups zu scannen, deren Metadatenbereiche zur WHERE-Klausel der Abfrage passen. Das Lesen der Metadaten jeder Gruppe hat allerdings einen gewissen Overhead.

Eine gute Faustregel: Die Anzahl der Row Groups pro Datei sollte mindestens so groß sein wie die Anzahl der CPU-Threads, die diese Datei abfragen. Mehr Row Groups über die Thread-Anzahl hinaus beschleunigen hochselektive Abfragen, verlangsamen aber Abfragen, die die ganze Datei scannen müssen, etwa Aggregationen.

Um eine Abfrage mit einer anderen Row-Group-Größe in eine Parquet-Datei zu schreiben, führen Sie aus:

COPY
(FROM generate_series(100_000))
TO 'row-groups.parquet'
(FORMAT parquet, ROW_GROUP_SIZE 100_000);

Die Option ROW_GROUPS_PER_FILE

Der Parameter ROW_GROUPS_PER_FILE erzeugt eine neue Parquet-Datei, sobald die aktuelle eine angegebene Anzahl von Row Groups hat.

COPY
(FROM generate_series(100_000))
TO 'output-directory'
(FORMAT parquet, ROW_GROUP_SIZE 20_000, ROW_GROUPS_PER_FILE 2);

Wenn mehrere Threads aktiv sind, kann die Anzahl der Row Groups in einer Datei die angegebene Anzahl leicht überschreiten, um das Locking zu begrenzen – analog zum Verhalten von FILE_SIZE_BYTES. Ist jedoch PER_THREAD_OUTPUT gesetzt, schreibt nur ein Thread in jede Datei, und die Angabe stimmt wieder genau.

Zeilen sortieren, um das Pruning von Row Groups zu verbessern

DuckDB schreibt pro Spalte Statistiken, einschließlich Min-/Max-Werten, für jede Row Group. Wie oben beschrieben nutzt der Reader diese, um Row Groups zu überspringen, die nicht zur WHERE-Klausel einer Abfrage passen können. Wenn Sie die Daten vor dem Schreiben nach den Spalten sortieren, nach denen Sie am häufigsten filtern, werden diese Min-/Max-Bereiche eng und überlappen sich zwischen Row Groups nicht. Hochselektive Abfragen auf diesen Spalten scannen dann deutlich weniger Row Groups:

COPY
(FROM 'events.parquet' ORDER BY event_time)
TO 'events-sorted.parquet'
(FORMAT parquet);

Das passt gut zu einer ROW_GROUP_SIZE, die jede Row Group auf einen engen Bereich des Sortierschlüssels konzentriert.

Weitere Tipps stehen im Leistungsleitfaden zu „File Formats“.