2024-06-26
Uns selbst über die Zeit benchmarken bei DuckDB
Alex Monahan
Ein großer Teil von DuckDBs Fokus liegt auf der Entwicklererfahrung beim Arbeiten mit Daten. Performance ist aber eine wichtige Überlegung, wenn man Datenmanagementsysteme untersucht. Datenverarbeitungssysteme fair mit Benchmarks zu vergleichen ist sehr schwierig. Wer den Benchmark anlegt, kennt wahrscheinlich ein System besser als die anderen, was die Benchmark-Auswahl, wie viel Zeit in Parameter-Tuning gesteckt wird, und mehr beeinflusst.
Stattdessen konzentriert sich dieser Beitrag darauf, unsere eigene Performance über die Zeit zu benchmarken.
Dieser Ansatz vermeidet viele Vergleichsfallen und liefert außerdem mehrere wertvolle Datenpunkte, die man bei der Systemauswahl berücksichtigen kann.
-
Wie schnell wird es besser? Ein neues Tool zu lernen ist eine Investition. Ein lebendiges, sich schnell verbesserndes Datenbanksystem zu wählen stellt sicher, dass Ihre Wahl sich über Jahre auszahlt. Plus: Wenn Sie ein Tool eine Weile nicht ausprobiert haben, können Sie sehen, wie viel schneller es seit dem letzten Check geworden ist!
-
Wofür ist es besonders gut? Die Wahl des Benchmarks ist ein Indikator dafür, für welche Arten von Workloads ein Tool nützlich ist. Je höher die Vielfalt der Analysen im Benchmark, desto breiter nützlich kann das Tool sein.
-
Welche Datenskalierung kann es handhaben? Viele Benchmarks sind bewusst kleiner als typische Workloads. Das erlaubt dem Benchmark, in angemessener Zeit fertig zu werden, wenn er mit vielen Konfigurationen läuft. Eine wichtige Frage bei der Systemauswahl ist aber, ob die Größe Ihrer Daten innerhalb der Größe Ihrer Compute-Ressourcen gehandhabt werden kann.
Es gibt einige Einschränkungen, wenn man die Performance eines Systems über die Zeit betrachtet. Ist ein Feature brandneu, gibt es keine vorherige Performance zum Vergleichen! Deshalb konzentriert sich dieser Beitrag auf grundlegende Workloads statt auf DuckDBs ständig wachsende Menge von Integrationen mit verschiedenen Lakehouse-Datenformaten, Cloud-Diensten und mehr.
Der Code, der den Benchmark ausführt, vermeidet auch viele von DuckDBs Friendlier-SQL-Ergänzungen, weil die ebenfalls später hinzugekommen sind. (Beim Schreiben dieser Abfragen fühlte es sich an, als würde man in der Zeit zurückgehen!)
Zusammenfassung des Benchmark-Designs
Dieser Beitrag misst DuckDBs Performance über die Zeit mit dem H2O.ai-Benchmark, plus ein paar neuen Benchmarks für Import, Export und Window Functions. Bitte siehe unsere vorherigen Blogposts für Details, warum wir den H2O.ai-Benchmark für einen guten Ansatz halten! Die vollständigen Details des Benchmark-Designs stehen im Anhang.
- H2O.ai, plus Import/Export- und Window-Function-Tests
- Python statt R
- 5-GB-Skala für alles, plus 50-GB-Skala für Group Bys und Joins
- Median von 3 Läufen
- Auf einem MacBook Pro M1 mit 16 GB RAM
- DuckDB-Versionen 0.2.7 bis 1.0.0
- Fast 3 Jahre, vom 14.06.2021 bis 03.06.2024
- Standardeinstellungen
- Pandas vor Version 0.5.1, Apache Arrow 0.5.1+
Gesamte Benchmark-Ergebnisse
Das neueste DuckDB kann einen Lauf der vollen Benchmark-Suite in unter 35 Sekunden abschließen, während Version 0.2.7 im Juni 2021 fast 500 Sekunden für dieselbe Aufgabe brauchte. Das ist 14-mal schneller, in nur 3 Jahren!
Performance über die Zeit
Note Diese Graphen sind interaktiv, dank Plotly.js! Filtern Sie gerne die verschiedenen Serien (einfacher Klick zum Ausblenden, Doppelklick, um nur diese Serie zu zeigen) und klicken-und-ziehen Sie zum Zoomen. Einzelne Benchmark-Ergebnisse sind beim Hover sichtbar.
Der Plot oben zeigt die Median-Laufzeit in Sekunden für alle Tests. Wegen der Vielfalt der Einsatzfälle für Window Functions und ihrer relativen algorithmischen Komplexität brauchen die 16 Window-Function-Tests die meiste Zeit aller Kategorien.
Dieser Plot normalisiert die Performance auf die neueste DuckDB-Version, um relative Verbesserungen über die Zeit zu zeigen. Schauen Sie auf den Zeitpunkt, zu dem Sie DuckDBs Performance zuletzt gemessen haben, zeigt Ihnen diese Zahl, wie oft schneller DuckDB jetzt ist!
Ein Teil der Gesamtverbesserung ist DuckDBs Hinzufügen von Multi-Threading, das im November 2021 mit Version 0.3.1 zum Standard wurde.
DuckDB ist in dieser Version auch zu einem Push-basierten Ausführungsmodell gewechselt, für zusätzliche Gewinne.
Paralleles Datenladen hat die Performance im Dezember 2022 mit Version 0.6.1 gesteigert, ebenso Verbesserungen am Kern-JOIN-Algorithmus.
Andere Verbesserungen erkunden wir später im Beitrag im Detail.
Wir sehen aber, dass alle Aspekte des Systems Verbesserungen gesehen haben, nicht nur die rohe Query-Performance! DuckDB konzentriert sich auf den gesamten Datenanalyse-Workflow, nicht nur auf Aggregat- oder Join-Performance. CSV-Parsing hat deutliche Gewinne gesehen, Import und Export haben sich deutlich verbessert, und Window Functions haben sich von allen am meisten verbessert.
Was war die leichte Regression von Dezember 2022 bis Juni 2023? Window Functions haben zusätzliche Fähigkeiten bekommen und dabei eine leichte Performance-Verschlechterung erfahren. Ab Juni 2023 sehen wir aber substanzielle Performance-Verbesserung über die ganze Breite bei Window Functions. Filtert man Window Functions aus dem Chart, sehen wir einen glatteren Trend.
Ihnen fällt vielleicht auch auf, dass die Performance ab Version 0.9 im September 2023 ein Plateau zu erreichen scheint. Was passiert hier? Erstmal nicht vergessen zu zoomen! Im letzten Jahr hat DuckDB immer noch über 3× verbessert! Kürzlich hat sich das DuckLabs-Team auf Skalierbarkeit konzentriert, indem es Algorithmen entwickelt hat, die Larger-than-Memory-Berechnungen unterstützen. Die Früchte dieser Arbeit sehen wir später im Skalen-Abschnitt! Zusätzlich hat sich DuckDB in den Versionen 0.10.1, 0.10.2 und 0.10.3 ausschließlich auf Bugfixes konzentriert, zur Vorbereitung auf ein besonders robustes DuckDB 1.0. Jetzt, da diese zwei großen Meilensteine (Larger-than-Memory-Berechnungen und DuckDB 1.0) erreicht sind, werden Performance-Verbesserungen wieder aufgenommen! Es ist erwähnenswert, dass der Boost durch den Wechsel zu Multi-Threading nur einmal auftritt, aber es gibt immer noch viele Chancen für die Zukunft.
Performance nach Version
Wir können den Gesamtplot auch nach Version statt nach Zeit neu erstellen. Das zeigt, dass DuckDB kürzlich häufigere Releases gemacht hat. Siehe DuckDBs Release-Kalender für die vollständige Versionshistorie.
Wenn Sie sich an die Version erinnern, die Sie zuletzt getestet haben, können Sie vergleichen, wie viel schneller die Dinge jetzt mit 1.0 sind!
Ergebnisse nach Workload
CSV-Reader
DuckDB hat substanziell in den Bau eines schnellen und robusten CSV-Parsers investiert. Das ist oft die erste Aufgabe in einem Datenanalyse-Workload und neigt dazu, unterbewertet und unterbenchmarkt zu werden. DuckDB hat die CSV-Reader-Performance um fast 3× verbessert, während es die Fähigkeit hinzugefügt hat, viele weitere CSV-Dialekte automatisch zu handhaben.
Group By
Group-by- oder Aggregationsoperationen sind kritische Schritte in OLAP-Workloads und haben deshalb substanziellen Fokus in DuckDB bekommen, mit einer Verbesserung von über 12× in den letzten 3 Jahren.
Im November 2021 hat Version 0.3.1 multithreaded Aggregation standardmäßig aktiviert und einen deutlichen Speedup geliefert.
Im Dezember 2022 wurden Datenloads in Tabellen mit dem Release von Version 0.6.1 parallelisiert. Das ist ein weiteres Beispiel dafür, den gesamten Daten-Workflow zu verbessern, weil dieser Group-by-Benchmark die Insert-Performance tatsächlich substanziell gestresst hat. Das Einfügen der Ergebnisse hat die Mehrheit der Zeit gebraucht!
Enums wurden in Version 0.6.1 auch anstelle von Strings für kategoriale Spalten genutzt. Das bedeutet, dass DuckDB Integers statt Strings nutzen konnte, wenn es auf diesen Spalten operierte, was die Performance weiter steigerte.
Trotz dessen, was auf den ersten Blick wie ein Performance-Plateau aussieht, zeigt Zoomen auf 2023 und 2024 eine ~20%-Verbesserung. Zusätzlich haben Aggregationen in den neuesten Versionen erhebliche Aufmerksamkeit bekommen, um Larger-than-Memory-Aggregationen zu ermöglichen. Sie können sehen, dass das erreicht wurde, während die Performance für den Smaller-than-Memory-Fall weiter verbessert wurde.
Join
Join-Operationen sind ein weiterer Fokusbereich für analytische Datenbanken und DuckDB im Besonderen. Join-Geschwindigkeiten haben sich in den letzten 3 Jahren um 4× verbessert!
Version 0.6.1 im Dezember 2022 hat Verbesserungen am Out-of-Core-Hash-Join eingeführt, die tatsächlich auch den Smaller-than-Memory-Fall verbessert haben. Paralleles Datenladen aus 0.6.1 hilft in diesem Benchmark ebenfalls, weil manche Ergebnisse dieselbe Größe wie die Eingabetabelle haben.
In neueren Versionen wurden Joins auch auf Larger-than-Memory-Fähigkeiten hochgerüstet. Dieser Fokus hat auch dem Smaller-than-Memory-Fall genutzt und zu den Verbesserungen in 0.10 geführt, das im Februar 2024 gestartet wurde.
Window Functions
Über den betrachteten Zeithorizont haben sich Window Functions dramatisch um 25× verbessert!
Die Window-Function-Performance wurde mit dem Release 0.9.0 im September 2023 substanziell verbessert. 14 verschiedene Performance-Optimierungen haben dazu beigetragen. Aggregatberechnung wurde vektorisiert (mit besonderem Fokus auf die Segment-Tree-Datenstruktur). Work Stealing hat multithreaded Verarbeitung ermöglicht, und das Sortieren wurde angepasst, um parallel zu laufen. Es wurde auch darauf geachtet, Speicher in größeren Batches vorzualloziieren.
DuckDBs Window Functions können auch Larger-than-Memory-Datensätze verarbeiten. Das Benchmarking dieses Features lassen wir für zukünftige Arbeit!
Export
Oft ist DuckDB nicht der letzte Schritt in einem Workflow, deshalb hat Export-Performance einen Einfluss. Exports sind jetzt 10× schneller! Bis vor kurzem war das DuckDB-Format nicht abwärtskompatibel, das empfohlene Langzeit-Persistenzformat war also Parquet. Parquet ist auch kritisch für die Interoperabilität mit vielen anderen Systemen, besonders Data Lakes. DuckDB funktioniert gut als Workflow-Engine, sodass der Export in andere In-Memory-Formate ebenfalls recht häufig ist.
Im Release September 2022 (Version 0.5.1) sehen wir deutliche Verbesserungen durch den Wechsel von Pandas zu Apache Arrow als empfohlenem In-Memory-Exportformat. DuckDBs zugrundeliegende Datentypen teilen viele Ähnlichkeiten mit Arrow, der Datentransfer ist also ziemlich schnell.
Die Parquet-Export-Performance hat sich über den Verlauf des Benchmarks um 4–5× verbessert, mit dramatischen Verbesserungen in den Versionen 0.8.1 (Juni 2023) und 0.10.2 (April 2024). Version 0.8.1 hat paralleles Parquet-Schreiben hinzugefügt und dabei die Insert-Reihenfolge erhalten.
Die Änderung, die die Verbesserung in 0.10.2 getrieben hat, war subtiler. Beim Exportieren von Strings mit hoher Kardinalität entscheidet DuckDB, ob Dictionary-Kompression gemacht wird oder nicht, je nachdem, ob sie die Dateigröße reduziert. Ab 0.10.2 wird das Kompressionsverhältnis getestet, nachdem eine Stichprobe der Werte ins Dictionary eingefügt wurde, statt nachdem alle Werte hinzugefügt sind. Das verhindert substanzielle unnötige Verarbeitung für High-Cardinality-Spalten, bei denen Dictionary-Kompression nicht hilft.
Apache Arrow vs. Pandas vs. Parquet exportieren
Dieser Plot zeigt die Performance aller drei Exportformate über den gesamten Zeithorizont (statt den Gewinner zwischen Pandas und Arrow zu wählen). Er erlaubt uns zu sehen, an welchem Punkt Apache Arrow Pandas in der Performance überholt.
Die Pandas-Export-Performance hat sich über den Verlauf des Benchmarks substanziell verbessert. Apache Arrow hat sich aber als das effizientere Datenformat erwiesen, deshalb wird Arrow jetzt für In-Memory-Exports bevorzugt. Interessant: DuckDBs Parquet-Export ist jetzt so effizient, dass es schneller ist, eine persistente Parquet-Datei zu schreiben, als in einen In-Memory-Pandas-Dataframe zu schreiben! Es ist sogar konkurrenzfähig mit Apache Arrow.
Andere Formate scannen
In manchen Einsatzfällen muss DuckDB die Rohdaten nicht speichern, sondern sollte sie einfach lesen und analysieren. Das erlaubt DuckDB, sich nahtlos in andere Workflows einzufügen. Dieser Benchmark misst, wie schnell DuckDB verschiedene Datenformate scannen und aggregieren kann.
Um Vergleiche über die Zeit zu ermöglichen, wechseln wir wie erwähnt bei Version 0.5.1 von Pandas zu Arrow. DuckDB ist in diesem Workload über 8× schneller, und die absolute benötigte Zeit ist sehr kurz. DuckDB passt hervorragend zu dieser Art von Arbeit!
Apache Arrow vs. Pandas vs. Parquet scannen
Wieder betrachten wir alle drei Formate über den gesamten Zeithorizont.
Beim Scannen von Daten sind Apache Arrow und Pandas in der Performance vergleichbarer. Deshalb: Während Arrow für Exports klar vorzuziehen ist, liest DuckDB Pandas gerne mit ähnlicher Geschwindigkeit. In diesem Fall erlauben die In-Memory-Natur von Arrow und Pandas ihnen aber, 2–3× schneller als Parquet zu sein. In absoluten Zahlen ist die Zeit, die diese Operation braucht, ein sehr kleiner Bruchteil des Benchmarks, andere Operationen sollten also der entscheidende Faktor sein.
Skalentests
Larger-than-Memory-Daten zu analysieren ist eine Superkraft für DuckDB und erlaubt es, für deutlich größere Datenanalyseaufgaben genutzt zu werden, als zuvor möglich waren.
In Version 0.9.0, gestartet im September 2023, wurde DuckDBs Hash-Aggregat erweitert, um Out-of-Core-(Larger-than-Memory-)Zwischenergebnisse zu handhaben. Die Details des Algorithmus, zusammen mit einigen Benchmarks, stehen in diesem Blogpost. Das erlaubt DuckDB, eine Milliarde Zeilen Daten (50 GB groß) auf einem MacBook Pro mit nur 16 GB RAM zu aggregieren, selbst wenn die Zahl eindeutiger Gruppen im Group By groß ist. Das repräsentiert mindestens eine 10× Verbesserung der Aggregatverarbeitungsskala über die 3 Jahre des Benchmarks.
DuckDBs Hash-Join-Operator unterstützt Larger-than-Memory-Joins seit Version 0.6.1 im Dezember 2022. Die Skala dieses Benchmarks (zusammen mit dem begrenzten RAM der Benchmark-Hardware) bedeutete aber, dass dieser Benchmark trotzdem nicht erfolgreich abschließen konnte. In Version 0.10.0, gestartet im Februar 2024, hat DuckDBs Speicherverwaltung ein signifikantes Upgrade bekommen, um mehrere nebenläufige Operatoren zu handhaben, die alle signifikanten Speicher brauchen. Der 0.10.0-Release-Blogpost teilt zusätzliche Details zu diesem Feature.
Als Ergebnis konnte DuckDB ab Version 0.10.0 Berechnungen auf Daten handhaben, die deutlich größer als der Speicher sind, selbst wenn die Zwischenberechnungen groß sind. Alle Operatoren werden unterstützt, einschließlich Sortieren, Aggregieren, Joinen und Windowing. Zukünftige Arbeit kann die Grenzen dessen, was mit DuckDBs Out-of-Core-Unterstützung möglich ist, weiter testen, einschließlich Window Functions und noch größerer Datengrößen.
Hardware-Fähigkeiten über die Zeit
DuckDBs Performance auf derselben Hardware hat sich dramatisch verbessert, und gleichzeitig nehmen die Fähigkeiten der Hardware ebenfalls schnell zu.
Quelle: [Our World in Data](https://ourworldindata.org/grapher/historical-cost-of-computer-memory-and-storage?yScale=linear&time=2021..latest&facet=metric&uniformYAxis=0)
Der Preis von RAM ist allein von 2021 bis 2023 um 2,2× gesunken, und der Preis von SSD-Speicher um 2,7×. Dank der Kombination aus DuckDB-Verbesserungen und Hardwarepreisen ist die Analysekala, die auf einem einzelnen Knoten möglich ist, in nur 3 Jahren um deutlich mehr als eine Größenordnung gestiegen!
Die Ergebnisse selbst analysieren
Eine DuckDB-1.0-Datenbank mit den Ergebnissen dieser Benchmarks ist verfügbar unter https://blobs.duckdb.org/data/duckdb_perf_over_time.duckdb.
Jeder DuckDB-Client mit der Extension httpfs kann diese Datei lesen.
Sie können sogar die DuckDB-Wasm-Web-Shell nutzen, um die Datei direkt aus Ihrem Browser abzufragen (mit vorausgefüllten und automatisch ausgeführten Abfragen!):
LOAD httpfs;ATTACH 'https://blobs.duckdb.org/data/duckdb_perf_over_time.duckdb' AS performance_results;USE performance_results;Die Datei enthält zwei Tabellen: benchmark_results und scale_benchmark_results.
Lassen Sie uns wissen, wenn Sie interessante Funde entdecken!
Fazit
Zusammengefasst: Nicht nur wächst DuckDBs Feature-Satz mit jedem Release substanziell, DuckDB wird auch sehr schnell schneller! Insgesamt hat sich die Performance in nur 3 Jahren um 14× verbessert!
Query-Performance ist aber nur ein Teil der Geschichte! Die Vielfalt der Workloads, die DuckDB handhaben kann, ist breit und wird breiter dank eines vollständigen SQL-Dialekts, einschließlich hochperformanter Window Functions. Zusätzlich haben sich kritische Workloads wie Datenimport, CSV-Parsing und Datenexport über die Zeit dramatisch verbessert. Die vollständige Entwicklererfahrung ist für DuckDB entscheidend!
Schließlich unterstützt DuckDB jetzt Larger-than-Memory-Berechnungen über alle Operatoren: Sortieren, Aggregieren, Joinen und Windowing. Die Größe des Problems, das Sie auf Ihren aktuellen Compute-Ressourcen handhaben können, ist gerade 10× größer geworden, oder mehr!
Wenn Sie es so weit geschafft haben: Willkommen in der Herde! 🦆 Kommen Sie zu uns auf Discord, wir schätzen Ihr Feedback!
Anhang
Benchmark-Design
H2O.ai als Grundlage
Dieser Beitrag misst DuckDBs Performance über die Zeit auf dem H2O.ai-Benchmark sowohl für Joins als auch für Group-by-Abfragen.
Das Ergebnis jeder H2O.ai-Abfrage wird in eine Tabelle in einer persistenten DuckDB-Datei geschrieben. Das erfordert zusätzliche Arbeit im Vergleich zu einem In-Memory-Workflow (besonders die Belastung der SSD statt des RAM), verbessert aber die Skalierbarkeit und ist ein üblicher Ansatz für größere Analysen.
Wie im aktuellen H2O.ai-Benchmark wurden kategoriale Spalten (VARCHAR-Spalten mit niedriger Kardinalität) als Teil des Benchmarks in den Typ ENUM umgewandelt.
Die Zeit für die Umwandlung in ENUM-Spalten war in der Benchmark-Zeit enthalten und führte zu einer niedrigeren Gesamtzeit (die Vorab-Umwandlung hat sich also gelohnt).
Der Datentyp ENUM war in DuckDB aber erst ab Version 0.6.1 (Dezember 2022) vollständig einsatzfähig, frühere Versionen überspringen diesen Schritt also.
Python-Client
Um Interoperabilität mit anderen Dataframe-Formaten zu messen, haben wir für diese Analyse Python statt R (von H2O.ai genutzt) verwendet. Wir nutzen R weiterhin für den Datenerzeugungsschritt, der Konsistenz mit dem Benchmark halber. Python ist DuckDBs beliebtester Client, großartig für Data Science und auch die Lieblingssprache des Autors für diese Art von Arbeit.
Export und Replacement Scans
Wir erweitern diesen Benchmark jetzt auf mehrere wichtige Weisen. Zusätzlich zur Betrachtung der rohen Query-Performance messen wir Import- und Export-Performance mit mehreren Formaten: Pandas, Apache Arrow und Apache Parquet. Die Ergebnisse sowohl der Join- als auch der Group-by-Benchmarks werden in jedes Format exportiert.
Beim Export in Dataframes haben wir die Performance in beiden Fällen gemessen. Beim Zusammenfassen der Gesamtperformance haben wir aber das zum jeweiligen Zeitpunkt beste Format gewählt. Das spiegelt wahrscheinlich das Verhalten performance-sensibler Nutzer wider (weil sie wahrscheinlich nicht in beide Formate schreiben würden!). In Version 0.5.1, veröffentlicht im September 2022, hat DuckDBs Performance beim Schreiben nach und Lesen aus dem Apache-Arrow-Format Pandas übertroffen. Deshalb nutzen die Versionen 0.2.7 bis 0.4.0 Pandas, und ab 0.5.1 Arrow.
Auf der Import-Seite erlauben Replacement Scans DuckDB, dieselben Formate ohne vorherigen Importschritt zu lesen. Im Replacement-Scan-Benchmark sind die gescannten Daten die Ausgabe der letzten H2O.ai-Group-by-Benchmark-Abfrage. Bei der 5-GB-Skala ist das ein 100-Millionen-Zeilen-Datensatz. Nur eine Spalte wird gelesen, und ein einzelnes Aggregat wird berechnet. Das konzentriert den Benchmark auf die Geschwindigkeit des Scannens der Daten statt auf DuckDBs Aggregationsalgorithmen oder die Geschwindigkeit der Ergebnisausgabe. Die genutzte Abfrage folgt dem Format:
SELECT sum(v3) AS v3FROM ⟨dataframe_or_Parquet_file⟩;Window Functions
Wir haben auch eine ganze Serie von Window-Function-Benchmarks hinzugefügt. Window Functions sind ein kritischer Workload in realen Datenanalyseszenarien und können ein System auf andere Weise stresstesten. DuckDB hat State-of-the-Art-Algorithmen implementiert, um selbst die komplexesten Window Functions schnell zu verarbeiten. Wir nutzen die größte Tabelle aus dem Join-Benchmark als Rohdaten für diese neuen Tests, um die Vergleichbarkeit mit dem Rest des Benchmarks zu unterstützen.
Window-Function-Benchmarks sind deutlich weniger üblich als traditionellere Joins und Aggregationen, und wir konnten keine geeignete Suite von der Stange finden. Diese Abfragen wurden entworfen, um die Vielfalt der Einsatzfälle für Window Functions zu zeigen, aber es gibt sicherlich mehr, die hinzugefügt werden könnten. Wir sind offen für Ihre Vorschläge für hinzuzufügende Abfragen und hoffen, dass diese Abfragen auch für andere Systeme nützlich sein könnten!
Da der Window-Functions-Benchmark neu ist, werden die Window Functions aus jeder der enthaltenen Abfragen im Anhang am Ende des Beitrags gezeigt.
Workload-Größe
Wir testen für die bisher genannten Workloads nur die mittlere 5-GB-Datensatzgröße, vor allem weil einige Import- und Export-Operationen in externe Formate wie Pandas in den Speicher passen müssen (und wir ein MacBook Pro M1 mit nur 16 GB RAM genutzt haben). Zusätzlich war das Ausführen der Tests für 21 DuckDB-Versionen selbst auf dieser Skala zeitintensiv, wegen der Performance älterer Versionen.
Skalentests
Nur 5 GB Daten zu nutzen beantwortet unsere zweite Schlüsselfrage der nicht: „Welche Datenskalierung kann es handhaben?“! Wir haben auch nur die Group-by- und Join-bezogenen Operationen (unter Vermeidung von In-Memory-Imports und -Exports) auf der 5-GB- und der 50-GB-Skala ausgeführt. Ältere DuckDB-Versionen konnten den 50-GB-Datensatz beim Joinen oder Aggregieren nicht handhaben, moderne Versionen können beides, selbst auf einem speicherbeschränkten 16-GB-RAM-Laptop. Statt Performance zu messen, messen wir die Größe des Benchmarks, der auf einer gegebenen Version abschließen konnte.
Zusammenfassungsmetriken
Mit Ausnahme der Skalentests wurde jeder Benchmark 3-mal ausgeführt, und die Median-Zeit wurde für die Ergebnisberichterstattung genutzt. Die Skalentests wurden einmal ausgeführt und erzeugten eine binäre Metrik, Erfolg oder Misserfolg, bei jeder getesteten Datengröße. Da ältere Versionen nicht elegant fehlschlagen würden, wurden die Skalenmetriken über mehrere Teilläufe gesammelt.
Compute-Ressourcen
Alle Tests nutzen ein MacBook Pro M1 mit 16 GB RAM. 2024 ist das weit entfernt vom State of the Art! Haben Sie leistungsfähigere Hardware, sehen Sie sowohl verbesserte Performance als auch Skalierbarkeit.
DuckDB-Versionen
Version 0.2.7, veröffentlicht im Juni 2021, war die erste Version mit einem für ARM64 kompilierten Python-Client, deshalb war sie die erste Version, die leicht auf den Benchmark-Compute-Ressourcen laufen konnte. Version 1.0.0 ist die neueste zum Zeitpunkt der Veröffentlichung (Juni 2024) verfügbare, obwohl wir auch einen Sneak Preview eines In-Development-Feature-Branch liefern.
Standardeinstellungen
Alle Versionen wurden mit den Standardeinstellungen ausgeführt. Deshalb erscheinen Verbesserungen durch ein neues Feature in diesen Ergebnissen erst, sobald dieses Feature zum Standard wurde und damit für Produktionsworkloads bereit war.
Window-Functions-Benchmark
Jede Benchmark-Abfrage folgt dem Format unten, aber mit unterschiedlichen Mengen von Window Functions im Platzhalter ⟨window_function(s)⟩{:.language-sql .highlight}.
Die genutzte Tabelle ist die größte Tabelle aus dem H2O.ai-Join-Benchmark, und in diesem Fall wurde die 5-GB-Skala genutzt.
DROP TABLE IF EXISTS windowing_results;
CREATE TABLE windowing_results AS SELECT id1, id2, id3, v2, ⟨window_function(s)⟩ FROM join_benchmark_largest_table;Die verschiedenen Window Functions, die den Platzhalter ersetzen, stehen unten und sind so beschriftet, dass sie zu den Ergebnisgraphen passen. Diese wurden ausgewählt, um die Vielfalt der Einsatzfälle für Window Functions zu zeigen sowie die Vielfalt der Algorithmen, die nötig sind, um den vollen Bereich der Syntax zu unterstützen. Die DuckDB-Dokumentation enthält ein vollständiges Railroad-Diagramm der verfügbaren Syntax. Gibt es übliche Einsatzfälle für Window Functions, die in diesem Benchmark nicht gut abgedeckt sind, lassen Sie es uns wissen!
/* 302 Basic Window */sum(v2) OVER () AS window_basic
/* 303 Sorted Window */first(v2) OVER (ORDER BY id3) AS first_order_by,row_number() OVER (ORDER BY id3) AS row_number_order_by
/* 304 Quantiles Entire Dataset */quantile_cont(v2, [0, 0.25, 0.50, 0.75, 1]) OVER () AS quantile_entire_dataset
/* 305 PARTITION BY */sum(v2) OVER (PARTITION BY id1) AS sum_by_id1,sum(v2) OVER (PARTITION BY id2) AS sum_by_id2,sum(v2) OVER (PARTITION BY id3) AS sum_by_id3
/* 306 PARTITION BY ORDER BY */first(v2) OVER (PARTITION BY id2 ORDER BY id3) AS first_by_id2_ordered_by_id3
/* 307 Lead and Lag */first(v2) OVER (ORDER BY id3 ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS my_lag,first(v2) OVER (ORDER BY id3 ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) AS my_lead
/* 308 Moving Averages */avg(v2) OVER (ORDER BY id3 ROWS BETWEEN 100 PRECEDING AND CURRENT ROW) AS my_moving_average,avg(v2) OVER (ORDER BY id3 ROWS BETWEEN id1 PRECEDING AND CURRENT ROW) AS my_dynamic_moving_average
/* 309 Rolling Sum */sum(v2) OVER (ORDER BY id3 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS my_rolling_sum
/* 310 RANGE BETWEEN */sum(v2) OVER (ORDER BY v2 RANGE BETWEEN 3 PRECEDING AND CURRENT ROW) AS my_range_between,sum(v2) OVER (ORDER BY v2 RANGE BETWEEN id1 PRECEDING AND CURRENT ROW) AS my_dynamic_range_between
/* 311 Quantiles PARTITION BY */quantile_cont(v2, [0, 0.25, 0.50, 0.75, 1]) OVER (PARTITION BY id2) AS my_quantiles_by_id2
/* 312 Quantiles PARTITION BY ROWS BETWEEN */first(v2) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS my_lag_by_id2,first(v2) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING) AS my_lead_by_id2
/* 313 Moving Averages PARTITION BY */avg(v2) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN 100 PRECEDING AND CURRENT ROW) AS my_moving_average_by_id2,avg(v2) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN id1 PRECEDING AND CURRENT ROW) AS my_dynamic_moving_average_by_id2
/* 314 Rolling Sum PARTITION BY */sum(v2) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS my_rolling_sum_by_id2
/* 315 RANGE BETWEEN PARTITION BY */sum(v2) OVER (PARTITION BY id2 ORDER BY v2 RANGE BETWEEN 3 PRECEDING AND CURRENT ROW) AS my_range_between_by_id2,sum(v2) OVER (PARTITION BY id2 ORDER BY v2 RANGE BETWEEN id1 PRECEDING AND CURRENT ROW) AS my_dynamic_range_between_by_id2
/* 316 Quantiles PARTITION BY ROWS BETWEEN */quantile_cont(v2, [0, 0.25, 0.50, 0.75, 1]) OVER (PARTITION BY id2 ORDER BY id3 ROWS BETWEEN 100 PRECEDING AND CURRENT ROW) AS my_quantiles_by_id2_rows_between