Benchmark-Suite
DuckDB hat eine umfangreiche Benchmark-Suite. Wenn Sie Änderungen vornehmen, die die Leistung beeinflussen können, sollten Sie diese Benchmarks ausführen, um mögliche Leistungsregressionen zu erkennen.
Erste Schritte
Um die Benchmark-Suite zu bauen, führen Sie im DuckDB-Repository den folgenden Befehl aus:
BUILD_BENCHMARK=1 BUILD_EXTENSIONS='tpch' makeBenchmarks auflisten
Um alle verfügbaren Benchmarks aufzulisten, führen Sie aus:
build/release/benchmark/benchmark_runner --listBenchmarks ausführen
Einen einzelnen Benchmark ausführen
Um einen einzelnen Benchmark auszuführen, geben Sie den folgenden Befehl ein:
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmarkDie Ausgabe wird im CSV-Format auf stdout geschrieben, in folgendem Format:
name run timingbenchmark/micro/nulls/no_nulls_addition.benchmark 1 0.121234benchmark/micro/nulls/no_nulls_addition.benchmark 2 0.121702benchmark/micro/nulls/no_nulls_addition.benchmark 3 0.122948benchmark/micro/nulls/no_nulls_addition.benchmark 4 0.122534benchmark/micro/nulls/no_nulls_addition.benchmark 5 0.124102Mit dem Flag --out können Sie auch eine Ausgabedatei angeben. Dann werden nur die Zeiten (durch Zeilenumbrüche getrennt) in diese Datei geschrieben.
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmark --out=timings.outDie Ausgabe enthält Folgendes:
0.1824720.1850270.1841630.1852810.182948Mehrere Benchmarks mit einem regulären Ausdruck ausführen
Sie können auch einen regulären Ausdruck angeben, um festzulegen, welche Benchmarks ausgeführt werden.
Achten Sie auf die Shell-Expansion bestimmter Regex-Zeichen (z. B. wird * wahrscheinlich von Ihrer Shell expandiert; das erfordert korrektes Quoting oder Escaping).
build/release/benchmark/benchmark_runner "benchmark/micro/nulls/.*"Alle Benchmarks ausführen
Ohne Argument werden alle Benchmarks ausgeführt.
build/release/benchmark/benchmark_runnerWeitere Optionen
Das Flag --info liefert weitere Informationen zum Benchmark.
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmark --infodisplay_name:NULL Addition (no nulls)group:microsubgroup:nullsDas Flag --query gibt die Abfrage aus, die der Benchmark ausführt.
SELECT min(i + 1) FROM integers;Das Flag --profile gibt einen Query-Tree aus.
Benchmarks erstellen
Ein Teil der Entwicklungsarbeit dreht sich um Leistung. Ein Benchmark neben den übrigen Tests bestätigt nicht nur Verbesserungen, sondern verhindert auch künftige Leistungsregressionen in der Funktion.
Benchmark-Beispiel
Zur Veranschaulichung, wie eine Benchmark-Datei aufgebaut ist, betrachten wir den Benchmark für die Window-Funktion FILL.
(Die Funktion FILL interpoliert fehlende Werte in einer geordneten Partition linear.)
Benchmarks ähneln Unit-Test-Dateien und haben denselben Kopfzeilentyp.
# description: Measure the performance of FILL# group: [window]Der Befehl make format-head stellt sicher, dass der Kopf die erwartete Struktur hat und verhindert Fehler der Tidy-Prüfung.
Unter diesem Kopf stehen Schlüsselwörter, die den Benchmark zusammenfassen.
name FillPerformancegroup microsubgroup windowManche Benchmarks führen eine einzelne Abfrage aus.
Oft ist es nützlich, einen Benchmark mit dem Schlüsselwort argument zu parametrisieren.
So lässt sich der Benchmark mit unterschiedlichen Einstellungen ausführen, etwa mit anderem Datenvolumen.
Für den FILL-Benchmark gibt es drei Argumente:
argument sf 10argument errors 0.1argument keys 4Für FILL sind das
- Der Scale Factor (Millionen Zeilen pro Partition)
- Die Fehlerrate (Anteil der fehlenden Werte)
- Die Anzahl der Partitionen.
Benchmarks erfordern in der Regel eine Datenvorbereitung, bevor die Abfrage läuft.
Die Datenvorbereitung steht im Abschnitt load der Benchmark-Datei.
Für den FILL-Benchmark erzeugen wir eine Tabelle mit den Parametern und einem Zufallszahlengenerator.
loadselect setseed(0.8675309);create or replace table data as ( select k::TINYINT as k, (case when random() > ${errors} then m - 1704067200000 else null end) as v, m, from range(1704067200000, 1704067200000 + ${sf} * 1_000_000 * 10, 10) times(m) cross join range(${keys}) keys(k));Die Parameter von argument werden in der Abfrage expandiert,
ähnlich wie foreach-Werte in Unit-Tests.
Im Abschnitt load können mehrere SQL-Anweisungen stehen.
Sind die Daten vorbereitet, können wir die Abfrage festlegen, die wir benchmarken!
Das geschieht im Abschnitt run. Die Einschränkungen sind dieselben wie bei einem Unit-Test
(z. B. keine Leerzeilen usw.).
Für den FILL-Benchmark wollen wir alle Stellen finden, an denen die Interpolation fehlschlägt:
runSELECT m, k, fill(v) OVER (PARTITION BY k ORDER BY m) as vFROM dataqualify v <> m - 1704067200000;Wenn die Interpolation korrekt ist, gibt es unabhängig vom Scale keine Ausgabe.
Das prüfen wir mit der abschließenden Klausel result,
die dieselbe Syntax wie ein Unit-Test hat:
result IIIOhne Ausgabezeilen prüfen wir sowohl die Korrektheit der Abfrage als auch ihre Leistung.
Es gibt viele weitere Beispiele im Verzeichnis benchmark/ auf der obersten Ebene,
und ein Blick dorthin lohnt sich, um weitere Techniken zu entdecken.