The index advantage
Build an index once and qsv can skip the opening scan on every run after. The payoff is lopsided — a ~6x jump for stats and ~3x for search, but next to nothing for streaming commands — so only the standouts are shown here.
see the qsv viz command
figs.append(viz("bar", index_src,
["--x", "command", "--y", "recs_per_sec", "--series", "index_status",
"--title", "The index advantage", "--y-title", "records/sec"],
"index_advantage", "The index advantage",
"Build an index once and qsv can skip the opening scan on every run after. "
"The payoff is lopsided — a ~6x jump for stats and ~3x for search, but next "
"to nothing for streaming commands — so only the standouts are shown here."))view on GitHub ↗ (gen_benchmark_viz.py, lines 563–569)count with an index is effectively instant
The index advantage at its extreme. With an index, count doesn't scan at all — it reads a row count qsv already stored, a ~10x jump from ~9M to ~90M rows/sec. It sits on its own axis precisely because that number would flatten every other bar on the page.
see the qsv viz command
figs.append(viz("bar", prep_count(),
["--x", "index_status", "--y", "recs_per_sec",
"--title", "count: the index-read superpower", "--y-title", "records/sec"],
"count_callout", "count with an index is effectively instant",
"The index advantage at its extreme. With an index, count doesn't scan at all — "
"it reads a row count qsv already stored, a ~10x jump from ~9M to ~90M rows/sec. "
"It sits on its own axis precisely because that number would flatten every "
"other bar on the page."))view on GitHub ↗ (gen_benchmark_viz.py, lines 570–577)The index superpowers
Some commands don't just skip the opening scan with an index — they skip almost all the work. slice and sample seek straight to the rows they need; schema reuses cached statistics. That's a different order of magnitude: schema runs 78x faster, and slice and sample tens of times over — versus the low single digits for the scan-skippers above.
see the qsv viz command
figs.append(viz("bar", sp_src,
["--x", "command", "--y", "speedup",
"--title", "The index superpowers — times faster with an index",
"--y-title", "× faster with an index"],
"index_superpowers", "The index superpowers",
"Some commands don't just skip the opening scan with an index — they skip almost "
"all the work. slice and sample seek straight to the rows they need; schema reuses "
f"cached statistics. That's a different order of magnitude: {sp_top_cmd} runs "
f"{sp_top_x:.0f}x faster, and slice and sample tens of times over — versus the "
"low single digits for the scan-skippers above."))view on GitHub ↗ (gen_benchmark_viz.py, lines 580–589)sqlp tuning: the schema-cache knob
sqlp infers a schema before it runs. Cache that schema and the re-inference cost disappears on the next query — worth about a third more throughput on these aggregations, for a one-line option.
see the qsv viz command
figs.append(viz("bar", prep_sqlp(),
["--x", "name", "--y", "recs_per_sec",
"--title", "sqlp tuning: the Polars schema-cache knob",
"--y-title", "records/sec"],
"sqlp_tuning", "sqlp tuning: the schema-cache knob",
"sqlp infers a schema before it runs. Cache that schema and the re-inference "
"cost disappears on the next query — worth about a third more throughput on "
"these aggregations, for a one-line option."))view on GitHub ↗ (gen_benchmark_viz.py, lines 590–597)The long view — every release
Records/sec for the marquee commands across all 59 releases since 0.113.0. Each line follows the fastest path available at the time: the plain scan early on, then the indexed variant once search and searchset learned to use an index at 10.0.0 — the visible step up. stats, frequency and validate carried their index from launch, so those lines run flat-to-up with no step. Broad trajectory only (see the note above); count is omitted for scale.
see the qsv viz command
figs.append(viz("line", prep_trend(),
["--x", "version", "--y", "recs_per_sec", "--series", "command",
"--title", f"Throughput across every release ({first_release} → {latest_release})",
"--y-title", "records/sec"],
"trend", "The long view — every release",
f"Records/sec for the marquee commands across all {n_releases} releases since "
f"{first_release}. Each line follows the fastest path available at the time: the "
"plain scan early on, then the indexed variant once search and searchset learned "
"to use an index at 10.0.0 — the visible step up. stats, frequency and validate "
"carried their index from launch, so those lines run flat-to-up with no step. "
"Broad trajectory only (see the note above); count is omitted for scale."))view on GitHub ↗ (gen_benchmark_viz.py, lines 598–608)Flagship deep-dive: stats
qsv's most-used command, indexed to its own launch speed. Over the years stats kept adding statistics — cardinality, quartiles, MAD, skewness — yet never got slower: plain stats now runs 1.8x its first-release speed, and the full --everything pass with an index 5.7x. Features grew; the curve still points up. (The odd single-release dip is a failed benchmark run, not a regression.)
see the qsv viz command
figs.append(viz("line", stats_src,
["--x", "version", "--y", "rel", "--series", "name",
"--title", "Flagship deep-dive: stats got richer AND faster",
"--y-title", "speed vs first release (1.0 = launch)"],
"stats_growth", "Flagship deep-dive: stats",
"qsv's most-used command, indexed to its own launch speed. Over the years stats "
"kept adding statistics — cardinality, quartiles, MAD, skewness — yet never got "
f"slower: plain stats now runs {s_base:.1f}x its first-release speed, and the "
f"full --everything pass with an index {s_heavy:.1f}x. Features grew; the curve "
"still points up. (The odd single-release dip is a failed benchmark run, not a "
"regression.)"))view on GitHub ↗ (gen_benchmark_viz.py, lines 616–626)Flagship deep-dive: frequency
The same story for qsv's second flagship. As frequency gained sorted, case-insensitive and unlimited modes, throughput climbed rather than eroded — base frequency is now 1.5x its launch speed and the indexed run 2.0x. Newer modes join partway, each measured from its own debut; the transient dips are measurement artifacts, not regressions.
see the qsv viz command
figs.append(viz("line", freq_src,
["--x", "version", "--y", "rel", "--series", "name",
"--title", "Flagship deep-dive: frequency held its ground",
"--y-title", "speed vs first release (1.0 = launch)"],
"freq_growth", "Flagship deep-dive: frequency",
"The same story for qsv's second flagship. As frequency gained sorted, "
"case-insensitive and unlimited modes, throughput climbed rather than eroded — "
f"base frequency is now {f_base:.1f}x its launch speed and the indexed run "
f"{f_idx:.1f}x. Newer modes join partway, each measured from its own debut; the "
"transient dips are measurement artifacts, not regressions."))view on GitHub ↗ (gen_benchmark_viz.py, lines 627–636)Flagship deep-dive: validate
qsv's data-quality workhorse, each variant indexed to its own launch speed. As validate gained modes — the fast no-schema structural pass, batch validation, dynamic-enum lookups, newer JSON Schema drafts — full JSON-Schema validation kept pace: validate_index now runs 1.3x its first-release speed. The no-schema structural path — the most parse-bound variant — dipped ~40% below launch from 17.0.0 through 21.0.0, when qsv's CSV parser (the csv-nose fork) moved to its 1.0.x line, then recovered sharply in 21.1.0 to 1.1x (back above launch) once csv-nose 1.1.0 landed SIMD UTF-8 validation and memchr-based scanning. Full-schema and no-schema paths are shown base vs index, each normalized to its own debut. (The sharp single-release spikes down — e.g. at 1.0.0 and 2.2.1 — are failed benchmark runs, not regressions.)
see the qsv viz command
figs.append(viz("line", validate_src,
["--x", "version", "--y", "rel", "--series", "name",
"--title", "Flagship deep-dive: validate",
"--y-title", "speed vs first release (1.0 = launch)"],
"validate_growth", "Flagship deep-dive: validate",
"qsv's data-quality workhorse, each variant indexed to its own launch speed. As "
"validate gained modes — the fast no-schema structural pass, batch validation, "
"dynamic-enum lookups, newer JSON Schema drafts — full JSON-Schema validation kept "
f"pace: validate_index now runs {v_idx:.1f}x its first-release speed. The no-schema "
"structural path — the most parse-bound variant — dipped ~40% below launch from "
"17.0.0 through 21.0.0, when qsv's CSV parser (the csv-nose fork) moved to its 1.0.x "
f"line, then recovered sharply in 21.1.0 to {v_ns_idx:.1f}x (back above launch) once "
"csv-nose 1.1.0 landed SIMD UTF-8 validation and memchr-based scanning. Full-schema "
"and no-schema paths are shown base vs index, each normalized to its own debut. (The "
"sharp single-release spikes down — e.g. at 1.0.0 and 2.2.1 — are failed benchmark "
"runs, not regressions.)"))view on GitHub ↗ (gen_benchmark_viz.py, lines 637–652)Relative throughput heatmap
The indexed marquee commands over the recent window, each row normalized to its own peak (1.0 = that command's fastest release). Normalizing per row lets a 90M-rows/sec count and a 600k-rows/sec frequency share one canvas — the colour shows trajectory, not absolute speed.
see the qsv viz command
figs.append(viz("heatmap", prep_heatmap(hm_versions),
["--x", "version", "--y", "name", "--z", "rel",
"--title", "Relative throughput vs each command's recent peak"],
"heatmap", "Relative throughput heatmap",
"The indexed marquee commands over the recent window, each row normalized to its "
"own peak (1.0 = that command's fastest release). Normalizing per row lets a "
"90M-rows/sec count and a 600k-rows/sec frequency share one canvas — the colour "
"shows trajectory, not absolute speed."))view on GitHub ↗ (gen_benchmark_viz.py, lines 653–660)Where the suite spends its time
The whole suite by wall-clock, family then benchmark. The biggest tiles are where a speedup would move the needle most — a map of where the optimization effort is best spent.
see the qsv viz command
figs.append(viz("treemap", prep_treemap(),
["--cols", "family,name", "--value", "mean", "--agg", "sum",
"--title", "Where the suite spends time (mean run time)"],
"time_spent", "Where the suite spends its time",
"The whole suite by wall-clock, family then benchmark. The biggest tiles are "
"where a speedup would move the needle most — a map of where the optimization "
"effort is best spent."))view on GitHub ↗ (gen_benchmark_viz.py, lines 661–667)Biggest speedups this release
The 15 benchmarks that improved most over the previous release. Bigger, brighter bubbles are larger wins — the percentage cut in mean run time from one version to the next.
see the qsv viz command
figs.append(viz("scatter", prep_gainers(),
["--x", "name", "--y", "delta (%)", "--size", "delta (%)", "--color", "delta (%)",
"--title", "Biggest speedups this release", "--y-title", "% faster vs previous version"],
"gainers", "Biggest speedups this release",
"The 15 benchmarks that improved most over the previous release. Bigger, brighter "
"bubbles are larger wins — the percentage cut in mean run time from one version "
"to the next."))view on GitHub ↗ (gen_benchmark_viz.py, lines 668–674)Change distribution by family
The wider view behind the speedups: the spread of per-release change within each family (above zero = faster). Most families cluster just north of zero — steady, unglamorous progress. Extreme outliers (|Δ| > 100%, usually measurement noise) are omitted; the y-axis is fixed to [-10, 55] so the boxes stay readable, clipping one bad-CI-run point (frequency_ignorecase, -79%).
see the qsv viz command
figs.append(viz("box", prep_delta_box(),
["--y", "delta (%)", "--x", "family",
"--title", "Release-over-release change by command family",
"--y-title", "% faster vs previous version",
# the real per-family boxes all sit within [-6, +51]; fix the axis to that
# window (with light padding) so a lone bad-CI-run outlier can't squash them
"--y-range=-10:55",
"--annotation",
"1 point clipped: frequency_ignorecase -79% (a bad CI run)"],
"change_by_family", "Change distribution by family",
"The wider view behind the speedups: the spread of per-release change within each "
"family (above zero = faster). Most families cluster just north of zero — steady, "
f"unglamorous progress. Extreme outliers (|Δ| > {int(DELTA_CLAMP)}%, usually "
"measurement noise) are omitted; the y-axis is fixed to [-10, 55] so the boxes "
"stay readable, clipping one bad-CI-run point (frequency_ignorecase, -79%)."))view on GitHub ↗ (gen_benchmark_viz.py, lines 675–689)