This is an automated email from the ASF dual-hosted git repository.

github-actions[bot] pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/datafusion-ballista.git


The following commit(s) were added to refs/heads/asf-site by this push:
     new 9bd23fc6c Publish built docs triggered by 
2c93670330d5204877ceca8f1f3d75de3ab3c82b
9bd23fc6c is described below

commit 9bd23fc6cfa28930ff7d2a637f9d1f6d0d9f050d
Author: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Jul 22 12:41:17 2026 +0000

    Publish built docs triggered by 2c93670330d5204877ceca8f1f3d75de3ab3c82b
---
 _sources/contributors-guide/benchmarking.md.txt | 202 +++++++++-----------
 contributors-guide/benchmarking.html            | 243 ++++++++----------------
 searchindex.js                                  |   2 +-
 3 files changed, 164 insertions(+), 283 deletions(-)

diff --git a/_sources/contributors-guide/benchmarking.md.txt 
b/_sources/contributors-guide/benchmarking.md.txt
index 88352e70d..94b608623 100644
--- a/_sources/contributors-guide/benchmarking.md.txt
+++ b/_sources/contributors-guide/benchmarking.md.txt
@@ -149,20 +149,24 @@ tpch benchmark ballista \
   --query 18 \
   --path /mnt/bigdata/tpch/sf1000 --format parquet \
   --partitions 64 --iterations 1 \
-  -c datafusion.optimizer.prefer_hash_join=false \
-  -c datafusion.optimizer.enable_dynamic_filter_pushdown=false \
   -c ballista.planner.adaptive.enabled=true
 ```
 
-Omit `--query` to run all 22. `ballista.planner.adaptive.enabled=true` is the 
AQE-on
-configuration these results use.
-
-`prefer_hash_join=false` makes DataFusion plan joins as `SortMergeJoin`, which 
is the
-join strategy this page compares across engines (Comet is configured to match, 
below).
-
-Note `datafusion.optimizer.enable_dynamic_filter_pushdown=false`: DataFusion's
-dynamic filter pushdown assumes single-process execution and can deadlock
-distributed execution, so it is pinned off for benchmark runs.
+Omit `--query` to run all 22, and add `--skip <n>` (repeatable) to leave 
individual
+queries out of that run — `--skip 18` is what produced the Ballista column 
below.
+`ballista.planner.adaptive.enabled=true` is the AQE-on configuration these 
results
+use.
+
+Note that `datafusion.optimizer.prefer_hash_join` is deliberately left at its 
default.
+Under AQE it does not select the join strategy: `DelayJoinSelectionRule` folds 
both
+`HashJoinExec` and `SortMergeJoinExec` into a single 
`DynamicJoinSelectionExec`, and
+the strategy is then chosen from runtime statistics — the broadcast 
thresholds, and
+`ballista.optimizer.hash_join_max_build_partition_bytes` (64 MiB by default), 
which
+lowers a Partitioned hash join to the spillable `SortMergeJoin` when the build 
side's
+largest partition would not fit. Setting `prefer_hash_join=false` does not 
force
+sort-merge; it only changes which conversion path the plan takes, and the
+`SortMergeJoinExec` path discards the join's projection, so it measures a 
slower plan
+rather than a different join strategy.
 
 ### Spark
 
@@ -222,9 +226,13 @@ spark-submit \
 ```
 
 `spark.comet.exec.replaceSortMergeJoin=false` keeps Comet on Spark's 
`SortMergeJoin`
-instead of converting it to a shuffled hash join. This matches Ballista, which 
plans
-`SortMergeJoin` (`prefer_hash_join=false`), so the two engines are compared on 
the
-same join strategy rather than one being handed a different one.
+instead of converting it to a shuffled hash join.
+
+This no longer pins the two engines to the same join strategy. Ballista under 
AQE
+chooses per join at runtime — broadcast, Partitioned hash, or sort-merge — and 
there
+is no supported way to force it to sort-merge throughout (see the note in the 
Ballista
+section above). So a Ballista-vs-Comet gap may partly reflect different join
+strategies, not only different execution. Read the comparison with that in 
mind.
 
 [comet]: https://datafusion.apache.org/comet/
 
@@ -264,61 +272,69 @@ planner.
 ## Results
 
 TPC-H **SF1000**, reference cluster above, **AQE on**, 1 iteration,
-`target_partitions=64`, `prefer_hash_join=false`,
-`enable_dynamic_filter_pushdown=false`, and the sort-shuffle spill cap 
overridden to
-uncapped (`ballista.shuffle.sort_based.memory_limit_per_task_bytes=0`; the 
shipped
-default is 256 MiB). All three engines plan `SortMergeJoin`. Times in seconds; 
lower
-is better.
+`target_partitions=64`, all Ballista join settings at their defaults. Ballista 
picks
+each join's strategy at runtime; Spark and Comet are held to `SortMergeJoin`. 
Times in
+seconds; lower is better.
 
 Versions under test:
 
 | Engine   | Version                                         |
 | -------- | ----------------------------------------------- |
-| Ballista | `#2084` @ `fac1fa22`                            |
+| Ballista | `#2124` @ `5290436d`                            |
 | Spark    | 3.5.3 (vanilla, Comet disabled)                 |
 | Comet    | `main` @ `b0165552` (1.0.0-SNAPSHOT, Spark 3.5) |
 
 Pin the **exact commit** the numbers came from, not "main": `main` moves, and 
a row
 that mixes numbers from different commits silently misattributes a regression.
 
-Ballista Q1–Q17 come from a **full 22-query suite run** (one query after 
another on
-freshly started executors); Q18 exhausts the memory pool and OOM-kills the 
executors
-(see below), which currently wedges the rest of the suite, so **Q19–Q22 were 
run as
-individual single-query jobs** against a fresh cluster of the same shape. 
Comet and
-Spark each completed the full suite in one run.
+The Ballista column comes from a **single suite run of 21 queries** on freshly
+started executors, using `--skip 18` to leave out the one query that exhausts 
the
+memory pool and OOM-kills the executors (see below), which would otherwise 
wedge
+the rest of the suite. Comet and Spark each completed the full suite in one 
run.
+
+Keep the whole column to one continuous run wherever possible. Driving queries 
as
+individual single-query jobs measures something different: each job starts 
against
+a cold page cache, which on this cluster cost the two join-free queries (Q1, 
Q6)
+roughly 20 s and 20 s respectively when the two methods were compared 
directly. Use
+`--skip` rather than a loop of `--query` runs.
+
+Single iteration means **run-to-run variance is not quantified here**. 
Comparing the
+same commit across the two methods above showed spreads of up to ~20% on 
individual
+queries, so treat a per-query difference under about 20% as noise and read the 
total
+row instead.
 
 |                 Query |      Spark |      Comet | Ballista (AQE on) |   Rows 
|
 | --------------------: | ---------: | ---------: | ----------------: | -----: 
|
-|                     1 |      427.1 |       46.6 |              59.4 |      4 
|
-|                     2 |       75.9 |       39.2 |              57.0 |    100 
|
-|                     3 |      154.1 |      195.4 |             214.8 |     10 
|
-|                     4 |       82.0 |       42.6 |              65.2 |      5 
|
-|                     5 |      336.4 |      493.4 |             456.6 |      5 
|
-|                     6 |       28.9 |       14.6 |              29.5 |      1 
|
-|                     7 |      180.6 |      149.5 |             369.0 |      4 
|
-|                     8 |      391.8 |      642.1 |             540.3 |      2 
|
-|                     9 |      509.8 |      843.5 |             764.9 |    175 
|
-|                    10 |      151.1 |      104.8 |             168.3 |     20 
|
-|                    11 |       44.7 |       44.1 |              91.4 |  0 [1] 
|
-|                    12 |       74.1 |       49.9 |              74.9 |      2 
|
-|                    13 |       98.7 |       58.3 |              91.9 |     30 
|
-|                    14 |       43.0 |       27.4 |              43.0 |      1 
|
-|                    15 |      121.5 |       65.6 |             116.5 |  1 [2] 
|
-|                    16 |       24.5 |       17.5 |              29.0 |  27840 
|
-|                    17 |      406.7 |      285.8 |             392.8 |      1 
|
-|                    18 |      428.8 |      370.5 |               OOM |    100 
|
-|                    19 |       58.9 |       35.5 |             183.9 |      1 
|
-|                    20 |      105.9 |       67.6 |             112.2 | 110759 
|
-|                    21 |      562.2 |      460.1 |             765.2 |    100 
|
-|                    22 |       36.8 |       21.5 |              35.2 |      7 
|
-| **Total (excl. Q18)** | **3914.7** | **3705.0** |        **4661.0** |        
|
-
-The **Total** row sums the 21 queries **excluding Q18**, because Q18 does not 
complete
-on Ballista at this sizing (below), so a 22-query total would not be 
comparable across
-engines. Q18's own times are in its row.
-
-Row counts agree across all three engines on every query, including Q18 (Spark 
and
-Comet return 100; Ballista OOMs before producing a result).
+|                     1 |      427.1 |       46.6 |              54.2 |      4 
|
+|                     2 |       75.9 |       39.2 |              60.3 |    100 
|
+|                     3 |      154.1 |      195.4 |             140.0 |     10 
|
+|                     4 |       82.0 |       42.6 |              46.3 |      5 
|
+|                     5 |      336.4 |      493.4 |             327.2 |      5 
|
+|                     6 |       28.9 |       14.6 |              27.2 |      1 
|
+|                     7 |      180.6 |      149.5 |             364.9 |      4 
|
+|                     8 |      391.8 |      642.1 |             481.1 |      2 
|
+|                     9 |      509.8 |      843.5 |             606.4 |    175 
|
+|                    10 |      151.1 |      104.8 |             148.4 |     20 
|
+|                    11 |       44.7 |       44.1 |              62.0 |  0 [1] 
|
+|                    12 |       74.1 |       49.9 |              58.3 |      2 
|
+|                    13 |       98.7 |       58.3 |             100.4 |     30 
|
+|                    14 |       43.0 |       27.4 |              71.1 |      1 
|
+|                    15 |      121.5 |       65.6 |              53.8 |  1 [2] 
|
+|                    16 |       24.5 |       17.5 |              34.3 |  27840 
|
+|                    17 |      406.7 |      285.8 |             417.8 |      1 
|
+|                    18 |      428.8 |      370.5 |               TBD |    100 
|
+|                    19 |       58.9 |       35.5 |              68.5 |      1 
|
+|                    20 |      105.9 |       67.6 |              93.7 | 110759 
|
+|                    21 |      562.2 |      460.1 |             698.0 |    100 
|
+|                    22 |       36.8 |       21.5 |              22.9 |      7 
|
+| **Total (excl. Q18)** | **3914.7** | **3705.0** |        **3936.8** |        
|
+
+The **Total** row sums the 21 queries **excluding Q18**, because Q18 has no 
Ballista
+figure at this commit (below), so a 22-query total would not be comparable 
across
+engines. Spark's and Comet's Q18 times are in its row.
+
+Row counts agree across all three engines on every query for which Ballista 
produced
+a result.
 
 The **AQE-off** Ballista column has been removed pending a re-run at a matched 
core
 count; the numbers above for AQE off were taken at a different executor size 
and are
@@ -331,12 +347,20 @@ constant is tuned for SF1.
 engines report 1 row here. (A previous result set saw Spark report 0 for Q15 
depending
 on which statement the harness took as the result; it does not recur in this 
run.)
 
-**Q18 OOMs on Ballista at this sizing.** Q18's hash-join build side is 
`Partitioned`
+**Q18 is not measured at this commit.** Q18's hash-join build side is 
`Partitioned`
 and does not spill; with 16 task slots sharing the 48 GB pool (3 GB per slot), 
the
 per-task build side exceeds the container limit and the executor is OOM-killed
 ([#2025](https://github.com/apache/datafusion-ballista/issues/2025)). At the 
previous
 8-slot sizing (6 GB per slot) Q18 completed, so this is a direct consequence 
of the
-denser packing. The OOM is recorded as `OOM` rather than a time.
+denser packing.
+
+It was excluded from the suite run above with `--skip 18` so that one query 
could not
+wedge the other 21, and it has not since been run to completion at this commit 
— hence
+`TBD` rather than `OOM`. An earlier attempt on this branch did OOM-kill an 
executor,
+but under a different configuration (`prefer_hash_join=false`, which sends the 
plan
+down a conversion path that discards the join's projection and so materialises 
more
+columns than the configuration documented above). That result does not 
transfer, so it
+is not recorded here.
 
 The `Rows` column is the row count the query returned, recorded so a time is 
never
 read without the answer it produced.
@@ -350,63 +374,6 @@ regression.
 did not produce an answer is recorded as `FAIL`, or `OOM` where the failure is 
a
 known memory exhaustion.
 
-### Hash join with a per-partition build-size fallback (AQE on, 2×16 cores, 64 
partitions)
-
-A second Ballista configuration exercises `prefer_hash_join=true` together 
with the
-AQE hash-join safety fallback
-([`ballista.optimizer.hash_join_max_build_partition_bytes`](https://github.com/apache/datafusion-ballista/pull/2084)).
-The fallback lowers a Partitioned hash join to `SortMergeJoin` per join when 
the
-build side's largest partition exceeds the configured budget, so a hash-join 
run does
-not abort on the queries whose non-spillable hash-join build exceeds one task 
slot's
-pool — notably Q18
-([#2025](https://github.com/apache/datafusion-ballista/issues/2025)). That 
fallback
-is what makes `prefer_hash_join=true` usable across the whole suite instead of
-failing partway.
-
-This run uses a **larger cluster than the reference above** and a **different
-`target_partitions`**, so its numbers are not comparable to the table above: 
TPC-H
-**SF1000**, **2 executors × 16 cores** (one per node, ~2.8 GB per task slot),
-**`target_partitions=64`**, **AQE on**, `prefer_hash_join=true`,
-`hash_join_max_build_partition_bytes=67108864` (64 MiB),
-`enable_dynamic_filter_pushdown=false`, sort-shuffle spill uncapped. Each 
query ran
-on a **freshly restarted cluster**. Ballista @ `afef9afc`. Times in seconds.
-
-|     Query | Ballista (AQE on, hash join + 64 MiB fallback) |
-| --------: | ---------------------------------------------: |
-|         1 |                                           72.1 |
-|         2 |                                           52.9 |
-|         3 |                                          154.2 |
-|         4 |                                           72.9 |
-|         5 |                                          355.4 |
-|         6 |                                           65.9 |
-|         7 |                                          371.7 |
-|         8 |                                          452.4 |
-|         9 |                                          559.8 |
-|        10 |                                          152.3 |
-|        11 |                                           74.6 |
-|        12 |                                           88.7 |
-|        13 |                                           99.2 |
-|        14 |                                           38.6 |
-|        15 |                                           62.5 |
-|        16 |                                           29.0 |
-|        17 |                                          446.3 |
-|        18 |                                          744.6 |
-|        19 |                                           80.8 |
-|        20 |                                          117.0 |
-|        21 |                                          605.6 |
-|        22 |                                           20.5 |
-| **Total** |                                     **4716.9** |
-
-**All 22 queries completed — no OOMs, no failures.** At the 64 MiB threshold 
the
-large-build joins (Q5, Q7–Q9, Q17, Q18, Q21) fall back to `SortMergeJoin` while
-smaller-build joins stay hash, so the heavy queries run at roughly sort-merge 
speed
-but the suite runs end to end. Q18 completes at **744.6 s** where the same
-configuration with the fallback disabled 
(`hash_join_max_build_partition_bytes=0`)
-exhausts the per-slot pool and fails the job
-([#2025](https://github.com/apache/datafusion-ballista/issues/2025)). The 
fallback is
-opt-in and off by default (a `0` budget); the 64 MiB value here is tuned to 
this
-cluster's ~2.8 GB task-slot pool.
-
 ### Recording a result
 
 - Pin the **exact commit** the numbers came from, not a branch name.
@@ -414,9 +381,10 @@ cluster's ~2.8 GB task-slot pool.
   configuration this page measures — from the same commit and cluster.
 - Prefer the figure from a **full suite run**, not a standalone single-query 
run: a
   long-lived executor deep into a suite is not in the same state as a freshly 
started
-  one. When a query cannot complete in-suite (e.g. Q18's OOM currently wedges 
the
-  run), note that the remaining queries were run individually, as done here for
-  Q19–Q22.
+  one, and a single-query job pays a cold-cache penalty that is large enough 
to swamp
+  the effect being measured. When a query cannot complete in-suite (e.g. Q18's 
OOM
+  currently wedges the run), exclude it with `--skip <n>` so the rest of the 
column
+  still comes from one continuous run, and measure that query separately.
 - Note the **row count** each query returned. A fast wrong answer is not a 
result,
   and distributed execution has produced silently wrong row counts before.
 - Flag any stage whose runtime is dominated by a few partitions — that is the
diff --git a/contributors-guide/benchmarking.html 
b/contributors-guide/benchmarking.html
index 634d1908d..384390bfe 100644
--- a/contributors-guide/benchmarking.html
+++ b/contributors-guide/benchmarking.html
@@ -521,18 +521,23 @@ ephemeral ports.</p>
 <span class="w">  </span>--query<span class="w"> </span><span 
class="m">18</span><span class="w"> </span><span class="se">\</span>
 <span class="w">  </span>--path<span class="w"> 
</span>/mnt/bigdata/tpch/sf1000<span class="w"> </span>--format<span class="w"> 
</span>parquet<span class="w"> </span><span class="se">\</span>
 <span class="w">  </span>--partitions<span class="w"> </span><span 
class="m">64</span><span class="w"> </span>--iterations<span class="w"> 
</span><span class="m">1</span><span class="w"> </span><span class="se">\</span>
-<span class="w">  </span>-c<span class="w"> 
</span>datafusion.optimizer.prefer_hash_join<span class="o">=</span><span 
class="nb">false</span><span class="w"> </span><span class="se">\</span>
-<span class="w">  </span>-c<span class="w"> 
</span>datafusion.optimizer.enable_dynamic_filter_pushdown<span 
class="o">=</span><span class="nb">false</span><span class="w"> </span><span 
class="se">\</span>
 <span class="w">  </span>-c<span class="w"> 
</span>ballista.planner.adaptive.enabled<span class="o">=</span><span 
class="nb">true</span>
 </pre></div>
 </div>
-<p>Omit <code class="docutils literal notranslate"><span 
class="pre">--query</span></code> to run all 22. <code class="docutils literal 
notranslate"><span 
class="pre">ballista.planner.adaptive.enabled=true</span></code> is the AQE-on
-configuration these results use.</p>
-<p><code class="docutils literal notranslate"><span 
class="pre">prefer_hash_join=false</span></code> makes DataFusion plan joins as 
<code class="docutils literal notranslate"><span 
class="pre">SortMergeJoin</span></code>, which is the
-join strategy this page compares across engines (Comet is configured to match, 
below).</p>
-<p>Note <code class="docutils literal notranslate"><span 
class="pre">datafusion.optimizer.enable_dynamic_filter_pushdown=false</span></code>:
 DataFusion’s
-dynamic filter pushdown assumes single-process execution and can deadlock
-distributed execution, so it is pinned off for benchmark runs.</p>
+<p>Omit <code class="docutils literal notranslate"><span 
class="pre">--query</span></code> to run all 22, and add <code class="docutils 
literal notranslate"><span class="pre">--skip</span> <span 
class="pre">&lt;n&gt;</span></code> (repeatable) to leave individual
+queries out of that run — <code class="docutils literal notranslate"><span 
class="pre">--skip</span> <span class="pre">18</span></code> is what produced 
the Ballista column below.
+<code class="docutils literal notranslate"><span 
class="pre">ballista.planner.adaptive.enabled=true</span></code> is the AQE-on 
configuration these results
+use.</p>
+<p>Note that <code class="docutils literal notranslate"><span 
class="pre">datafusion.optimizer.prefer_hash_join</span></code> is deliberately 
left at its default.
+Under AQE it does not select the join strategy: <code class="docutils literal 
notranslate"><span class="pre">DelayJoinSelectionRule</span></code> folds both
+<code class="docutils literal notranslate"><span 
class="pre">HashJoinExec</span></code> and <code class="docutils literal 
notranslate"><span class="pre">SortMergeJoinExec</span></code> into a single 
<code class="docutils literal notranslate"><span 
class="pre">DynamicJoinSelectionExec</span></code>, and
+the strategy is then chosen from runtime statistics — the broadcast 
thresholds, and
+<code class="docutils literal notranslate"><span 
class="pre">ballista.optimizer.hash_join_max_build_partition_bytes</span></code>
 (64 MiB by default), which
+lowers a Partitioned hash join to the spillable <code class="docutils literal 
notranslate"><span class="pre">SortMergeJoin</span></code> when the build side’s
+largest partition would not fit. Setting <code class="docutils literal 
notranslate"><span class="pre">prefer_hash_join=false</span></code> does not 
force
+sort-merge; it only changes which conversion path the plan takes, and the
+<code class="docutils literal notranslate"><span 
class="pre">SortMergeJoinExec</span></code> path discards the join’s 
projection, so it measures a slower plan
+rather than a different join strategy.</p>
 </section>
 <section id="spark">
 <h3>Spark<a class="headerlink" href="#spark" title="Link to this 
heading">#</a></h3>
@@ -588,9 +593,12 @@ the Comet shuffle manager, and the jar on the 
classpath:</p>
 </pre></div>
 </div>
 <p><code class="docutils literal notranslate"><span 
class="pre">spark.comet.exec.replaceSortMergeJoin=false</span></code> keeps 
Comet on Spark’s <code class="docutils literal notranslate"><span 
class="pre">SortMergeJoin</span></code>
-instead of converting it to a shuffled hash join. This matches Ballista, which 
plans
-<code class="docutils literal notranslate"><span 
class="pre">SortMergeJoin</span></code> (<code class="docutils literal 
notranslate"><span class="pre">prefer_hash_join=false</span></code>), so the 
two engines are compared on the
-same join strategy rather than one being handed a different one.</p>
+instead of converting it to a shuffled hash join.</p>
+<p>This no longer pins the two engines to the same join strategy. Ballista 
under AQE
+chooses per join at runtime — broadcast, Partitioned hash, or sort-merge — and 
there
+is no supported way to force it to sort-merge throughout (see the note in the 
Ballista
+section above). So a Ballista-vs-Comet gap may partly reflect different join
+strategies, not only different execution. Read the comparison with that in 
mind.</p>
 </section>
 </section>
 <section id="why-compare-against-comet">
@@ -628,11 +636,9 @@ planner.</p>
 <section id="results">
 <h2>Results<a class="headerlink" href="#results" title="Link to this 
heading">#</a></h2>
 <p>TPC-H <strong>SF1000</strong>, reference cluster above, <strong>AQE 
on</strong>, 1 iteration,
-<code class="docutils literal notranslate"><span 
class="pre">target_partitions=64</span></code>, <code class="docutils literal 
notranslate"><span class="pre">prefer_hash_join=false</span></code>,
-<code class="docutils literal notranslate"><span 
class="pre">enable_dynamic_filter_pushdown=false</span></code>, and the 
sort-shuffle spill cap overridden to
-uncapped (<code class="docutils literal notranslate"><span 
class="pre">ballista.shuffle.sort_based.memory_limit_per_task_bytes=0</span></code>;
 the shipped
-default is 256 MiB). All three engines plan <code class="docutils literal 
notranslate"><span class="pre">SortMergeJoin</span></code>. Times in seconds; 
lower
-is better.</p>
+<code class="docutils literal notranslate"><span 
class="pre">target_partitions=64</span></code>, all Ballista join settings at 
their defaults. Ballista picks
+each join’s strategy at runtime; Spark and Comet are held to <code 
class="docutils literal notranslate"><span 
class="pre">SortMergeJoin</span></code>. Times in
+seconds; lower is better.</p>
 <p>Versions under test:</p>
 <div class="pst-scrollable-table-container"><table class="table">
 <thead>
@@ -642,7 +648,7 @@ is better.</p>
 </thead>
 <tbody>
 <tr class="row-even"><td><p>Ballista</p></td>
-<td><p><code class="docutils literal notranslate"><span 
class="pre">#2084</span></code> &#64; <code class="docutils literal 
notranslate"><span class="pre">fac1fa22</span></code></p></td>
+<td><p><code class="docutils literal notranslate"><span 
class="pre">#2124</span></code> &#64; <code class="docutils literal 
notranslate"><span class="pre">5290436d</span></code></p></td>
 </tr>
 <tr class="row-odd"><td><p>Spark</p></td>
 <td><p>3.5.3 (vanilla, Comet disabled)</p></td>
@@ -655,11 +661,19 @@ is better.</p>
 </div>
 <p>Pin the <strong>exact commit</strong> the numbers came from, not “main”: 
<code class="docutils literal notranslate"><span class="pre">main</span></code> 
moves, and a row
 that mixes numbers from different commits silently misattributes a 
regression.</p>
-<p>Ballista Q1–Q17 come from a <strong>full 22-query suite run</strong> (one 
query after another on
-freshly started executors); Q18 exhausts the memory pool and OOM-kills the 
executors
-(see below), which currently wedges the rest of the suite, so <strong>Q19–Q22 
were run as
-individual single-query jobs</strong> against a fresh cluster of the same 
shape. Comet and
-Spark each completed the full suite in one run.</p>
+<p>The Ballista column comes from a <strong>single suite run of 21 
queries</strong> on freshly
+started executors, using <code class="docutils literal notranslate"><span 
class="pre">--skip</span> <span class="pre">18</span></code> to leave out the 
one query that exhausts the
+memory pool and OOM-kills the executors (see below), which would otherwise 
wedge
+the rest of the suite. Comet and Spark each completed the full suite in one 
run.</p>
+<p>Keep the whole column to one continuous run wherever possible. Driving 
queries as
+individual single-query jobs measures something different: each job starts 
against
+a cold page cache, which on this cluster cost the two join-free queries (Q1, 
Q6)
+roughly 20 s and 20 s respectively when the two methods were compared 
directly. Use
+<code class="docutils literal notranslate"><span 
class="pre">--skip</span></code> rather than a loop of <code class="docutils 
literal notranslate"><span class="pre">--query</span></code> runs.</p>
+<p>Single iteration means <strong>run-to-run variance is not quantified 
here</strong>. Comparing the
+same commit across the two methods above showed spreads of up to ~20% on 
individual
+queries, so treat a per-query difference under about 20% as noise and read the 
total
+row instead.</p>
 <div class="pst-scrollable-table-container"><table class="table">
 <thead>
 <tr class="row-odd"><th class="head text-right"><p>Query</p></th>
@@ -673,149 +687,149 @@ Spark each completed the full suite in one run.</p>
 <tr class="row-even"><td class="text-right"><p>1</p></td>
 <td class="text-right"><p>427.1</p></td>
 <td class="text-right"><p>46.6</p></td>
-<td class="text-right"><p>59.4</p></td>
+<td class="text-right"><p>54.2</p></td>
 <td class="text-right"><p>4</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>2</p></td>
 <td class="text-right"><p>75.9</p></td>
 <td class="text-right"><p>39.2</p></td>
-<td class="text-right"><p>57.0</p></td>
+<td class="text-right"><p>60.3</p></td>
 <td class="text-right"><p>100</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>3</p></td>
 <td class="text-right"><p>154.1</p></td>
 <td class="text-right"><p>195.4</p></td>
-<td class="text-right"><p>214.8</p></td>
+<td class="text-right"><p>140.0</p></td>
 <td class="text-right"><p>10</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>4</p></td>
 <td class="text-right"><p>82.0</p></td>
 <td class="text-right"><p>42.6</p></td>
-<td class="text-right"><p>65.2</p></td>
+<td class="text-right"><p>46.3</p></td>
 <td class="text-right"><p>5</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>5</p></td>
 <td class="text-right"><p>336.4</p></td>
 <td class="text-right"><p>493.4</p></td>
-<td class="text-right"><p>456.6</p></td>
+<td class="text-right"><p>327.2</p></td>
 <td class="text-right"><p>5</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>6</p></td>
 <td class="text-right"><p>28.9</p></td>
 <td class="text-right"><p>14.6</p></td>
-<td class="text-right"><p>29.5</p></td>
+<td class="text-right"><p>27.2</p></td>
 <td class="text-right"><p>1</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>7</p></td>
 <td class="text-right"><p>180.6</p></td>
 <td class="text-right"><p>149.5</p></td>
-<td class="text-right"><p>369.0</p></td>
+<td class="text-right"><p>364.9</p></td>
 <td class="text-right"><p>4</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>8</p></td>
 <td class="text-right"><p>391.8</p></td>
 <td class="text-right"><p>642.1</p></td>
-<td class="text-right"><p>540.3</p></td>
+<td class="text-right"><p>481.1</p></td>
 <td class="text-right"><p>2</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>9</p></td>
 <td class="text-right"><p>509.8</p></td>
 <td class="text-right"><p>843.5</p></td>
-<td class="text-right"><p>764.9</p></td>
+<td class="text-right"><p>606.4</p></td>
 <td class="text-right"><p>175</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>10</p></td>
 <td class="text-right"><p>151.1</p></td>
 <td class="text-right"><p>104.8</p></td>
-<td class="text-right"><p>168.3</p></td>
+<td class="text-right"><p>148.4</p></td>
 <td class="text-right"><p>20</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>11</p></td>
 <td class="text-right"><p>44.7</p></td>
 <td class="text-right"><p>44.1</p></td>
-<td class="text-right"><p>91.4</p></td>
+<td class="text-right"><p>62.0</p></td>
 <td class="text-right"><p>0 [1]</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>12</p></td>
 <td class="text-right"><p>74.1</p></td>
 <td class="text-right"><p>49.9</p></td>
-<td class="text-right"><p>74.9</p></td>
+<td class="text-right"><p>58.3</p></td>
 <td class="text-right"><p>2</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>13</p></td>
 <td class="text-right"><p>98.7</p></td>
 <td class="text-right"><p>58.3</p></td>
-<td class="text-right"><p>91.9</p></td>
+<td class="text-right"><p>100.4</p></td>
 <td class="text-right"><p>30</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>14</p></td>
 <td class="text-right"><p>43.0</p></td>
 <td class="text-right"><p>27.4</p></td>
-<td class="text-right"><p>43.0</p></td>
+<td class="text-right"><p>71.1</p></td>
 <td class="text-right"><p>1</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>15</p></td>
 <td class="text-right"><p>121.5</p></td>
 <td class="text-right"><p>65.6</p></td>
-<td class="text-right"><p>116.5</p></td>
+<td class="text-right"><p>53.8</p></td>
 <td class="text-right"><p>1 [2]</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>16</p></td>
 <td class="text-right"><p>24.5</p></td>
 <td class="text-right"><p>17.5</p></td>
-<td class="text-right"><p>29.0</p></td>
+<td class="text-right"><p>34.3</p></td>
 <td class="text-right"><p>27840</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>17</p></td>
 <td class="text-right"><p>406.7</p></td>
 <td class="text-right"><p>285.8</p></td>
-<td class="text-right"><p>392.8</p></td>
+<td class="text-right"><p>417.8</p></td>
 <td class="text-right"><p>1</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>18</p></td>
 <td class="text-right"><p>428.8</p></td>
 <td class="text-right"><p>370.5</p></td>
-<td class="text-right"><p>OOM</p></td>
+<td class="text-right"><p>TBD</p></td>
 <td class="text-right"><p>100</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>19</p></td>
 <td class="text-right"><p>58.9</p></td>
 <td class="text-right"><p>35.5</p></td>
-<td class="text-right"><p>183.9</p></td>
+<td class="text-right"><p>68.5</p></td>
 <td class="text-right"><p>1</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>20</p></td>
 <td class="text-right"><p>105.9</p></td>
 <td class="text-right"><p>67.6</p></td>
-<td class="text-right"><p>112.2</p></td>
+<td class="text-right"><p>93.7</p></td>
 <td class="text-right"><p>110759</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p>21</p></td>
 <td class="text-right"><p>562.2</p></td>
 <td class="text-right"><p>460.1</p></td>
-<td class="text-right"><p>765.2</p></td>
+<td class="text-right"><p>698.0</p></td>
 <td class="text-right"><p>100</p></td>
 </tr>
 <tr class="row-odd"><td class="text-right"><p>22</p></td>
 <td class="text-right"><p>36.8</p></td>
 <td class="text-right"><p>21.5</p></td>
-<td class="text-right"><p>35.2</p></td>
+<td class="text-right"><p>22.9</p></td>
 <td class="text-right"><p>7</p></td>
 </tr>
 <tr class="row-even"><td class="text-right"><p><strong>Total (excl. 
Q18)</strong></p></td>
 <td class="text-right"><p><strong>3914.7</strong></p></td>
 <td class="text-right"><p><strong>3705.0</strong></p></td>
-<td class="text-right"><p><strong>4661.0</strong></p></td>
+<td class="text-right"><p><strong>3936.8</strong></p></td>
 <td class="text-right"><p></p></td>
 </tr>
 </tbody>
 </table>
 </div>
-<p>The <strong>Total</strong> row sums the 21 queries <strong>excluding 
Q18</strong>, because Q18 does not complete
-on Ballista at this sizing (below), so a 22-query total would not be 
comparable across
-engines. Q18’s own times are in its row.</p>
-<p>Row counts agree across all three engines on every query, including Q18 
(Spark and
-Comet return 100; Ballista OOMs before producing a result).</p>
+<p>The <strong>Total</strong> row sums the 21 queries <strong>excluding 
Q18</strong>, because Q18 has no Ballista
+figure at this commit (below), so a 22-query total would not be comparable 
across
+engines. Spark’s and Comet’s Q18 times are in its row.</p>
+<p>Row counts agree across all three engines on every query for which Ballista 
produced
+a result.</p>
 <p>The <strong>AQE-off</strong> Ballista column has been removed pending a 
re-run at a matched core
 count; the numbers above for AQE off were taken at a different executor size 
and are
 not comparable to a fresh AQE-off run, so they were dropped rather than left 
stale.</p>
@@ -824,12 +838,19 @@ constant is tuned for SF1.</p>
 <p>[2] Q15 is a multi-statement query (<code class="docutils literal 
notranslate"><span class="pre">CREATE</span> <span 
class="pre">VIEW</span></code> / <code class="docutils literal 
notranslate"><span class="pre">SELECT</span></code> / <code class="docutils 
literal notranslate"><span class="pre">DROP</span> <span 
class="pre">VIEW</span></code>); all three
 engines report 1 row here. (A previous result set saw Spark report 0 for Q15 
depending
 on which statement the harness took as the result; it does not recur in this 
run.)</p>
-<p><strong>Q18 OOMs on Ballista at this sizing.</strong> Q18’s hash-join build 
side is <code class="docutils literal notranslate"><span 
class="pre">Partitioned</span></code>
+<p><strong>Q18 is not measured at this commit.</strong> Q18’s hash-join build 
side is <code class="docutils literal notranslate"><span 
class="pre">Partitioned</span></code>
 and does not spill; with 16 task slots sharing the 48 GB pool (3 GB per slot), 
the
 per-task build side exceeds the container limit and the executor is OOM-killed
 (<a class="reference external" 
href="https://github.com/apache/datafusion-ballista/issues/2025";>#2025</a>). At 
the previous
 8-slot sizing (6 GB per slot) Q18 completed, so this is a direct consequence 
of the
-denser packing. The OOM is recorded as <code class="docutils literal 
notranslate"><span class="pre">OOM</span></code> rather than a time.</p>
+denser packing.</p>
+<p>It was excluded from the suite run above with <code class="docutils literal 
notranslate"><span class="pre">--skip</span> <span class="pre">18</span></code> 
so that one query could not
+wedge the other 21, and it has not since been run to completion at this commit 
— hence
+<code class="docutils literal notranslate"><span class="pre">TBD</span></code> 
rather than <code class="docutils literal notranslate"><span 
class="pre">OOM</span></code>. An earlier attempt on this branch did OOM-kill 
an executor,
+but under a different configuration (<code class="docutils literal 
notranslate"><span class="pre">prefer_hash_join=false</span></code>, which 
sends the plan
+down a conversion path that discards the join’s projection and so materialises 
more
+columns than the configuration documented above). That result does not 
transfer, so it
+is not recorded here.</p>
 <p>The <code class="docutils literal notranslate"><span 
class="pre">Rows</span></code> column is the row count the query returned, 
recorded so a time is never
 read without the answer it produced.</p>
 <p>This table records <strong>one current result set</strong>. When results 
are refreshed, the
@@ -839,114 +860,6 @@ regression.</p>
 <p><code class="docutils literal notranslate"><span 
class="pre">TBD</span></code> means not yet measured on this cluster at this 
commit; a query that ran but
 did not produce an answer is recorded as <code class="docutils literal 
notranslate"><span class="pre">FAIL</span></code>, or <code class="docutils 
literal notranslate"><span class="pre">OOM</span></code> where the failure is a
 known memory exhaustion.</p>
-<section 
id="hash-join-with-a-per-partition-build-size-fallback-aqe-on-216-cores-64-partitions">
-<h3>Hash join with a per-partition build-size fallback (AQE on, 2×16 cores, 64 
partitions)<a class="headerlink" 
href="#hash-join-with-a-per-partition-build-size-fallback-aqe-on-216-cores-64-partitions"
 title="Link to this heading">#</a></h3>
-<p>A second Ballista configuration exercises <code class="docutils literal 
notranslate"><span class="pre">prefer_hash_join=true</span></code> together 
with the
-AQE hash-join safety fallback
-(<a class="reference external" 
href="https://github.com/apache/datafusion-ballista/pull/2084";><code 
class="docutils literal notranslate"><span 
class="pre">ballista.optimizer.hash_join_max_build_partition_bytes</span></code></a>).
-The fallback lowers a Partitioned hash join to <code class="docutils literal 
notranslate"><span class="pre">SortMergeJoin</span></code> per join when the
-build side’s largest partition exceeds the configured budget, so a hash-join 
run does
-not abort on the queries whose non-spillable hash-join build exceeds one task 
slot’s
-pool — notably Q18
-(<a class="reference external" 
href="https://github.com/apache/datafusion-ballista/issues/2025";>#2025</a>). 
That fallback
-is what makes <code class="docutils literal notranslate"><span 
class="pre">prefer_hash_join=true</span></code> usable across the whole suite 
instead of
-failing partway.</p>
-<p>This run uses a <strong>larger cluster than the reference above</strong> 
and a <strong>different
-<code class="docutils literal notranslate"><span 
class="pre">target_partitions</span></code></strong>, so its numbers are not 
comparable to the table above: TPC-H
-<strong>SF1000</strong>, <strong>2 executors × 16 cores</strong> (one per 
node, ~2.8 GB per task slot),
-<strong><code class="docutils literal notranslate"><span 
class="pre">target_partitions=64</span></code></strong>, <strong>AQE 
on</strong>, <code class="docutils literal notranslate"><span 
class="pre">prefer_hash_join=true</span></code>,
-<code class="docutils literal notranslate"><span 
class="pre">hash_join_max_build_partition_bytes=67108864</span></code> (64 MiB),
-<code class="docutils literal notranslate"><span 
class="pre">enable_dynamic_filter_pushdown=false</span></code>, sort-shuffle 
spill uncapped. Each query ran
-on a <strong>freshly restarted cluster</strong>. Ballista &#64; <code 
class="docutils literal notranslate"><span class="pre">afef9afc</span></code>. 
Times in seconds.</p>
-<div class="pst-scrollable-table-container"><table class="table">
-<thead>
-<tr class="row-odd"><th class="head text-right"><p>Query</p></th>
-<th class="head text-right"><p>Ballista (AQE on, hash join + 64 MiB 
fallback)</p></th>
-</tr>
-</thead>
-<tbody>
-<tr class="row-even"><td class="text-right"><p>1</p></td>
-<td class="text-right"><p>72.1</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>2</p></td>
-<td class="text-right"><p>52.9</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>3</p></td>
-<td class="text-right"><p>154.2</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>4</p></td>
-<td class="text-right"><p>72.9</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>5</p></td>
-<td class="text-right"><p>355.4</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>6</p></td>
-<td class="text-right"><p>65.9</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>7</p></td>
-<td class="text-right"><p>371.7</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>8</p></td>
-<td class="text-right"><p>452.4</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>9</p></td>
-<td class="text-right"><p>559.8</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>10</p></td>
-<td class="text-right"><p>152.3</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>11</p></td>
-<td class="text-right"><p>74.6</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>12</p></td>
-<td class="text-right"><p>88.7</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>13</p></td>
-<td class="text-right"><p>99.2</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>14</p></td>
-<td class="text-right"><p>38.6</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>15</p></td>
-<td class="text-right"><p>62.5</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>16</p></td>
-<td class="text-right"><p>29.0</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>17</p></td>
-<td class="text-right"><p>446.3</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>18</p></td>
-<td class="text-right"><p>744.6</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>19</p></td>
-<td class="text-right"><p>80.8</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>20</p></td>
-<td class="text-right"><p>117.0</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p>21</p></td>
-<td class="text-right"><p>605.6</p></td>
-</tr>
-<tr class="row-odd"><td class="text-right"><p>22</p></td>
-<td class="text-right"><p>20.5</p></td>
-</tr>
-<tr class="row-even"><td class="text-right"><p><strong>Total</strong></p></td>
-<td class="text-right"><p><strong>4716.9</strong></p></td>
-</tr>
-</tbody>
-</table>
-</div>
-<p><strong>All 22 queries completed — no OOMs, no failures.</strong> At the 64 
MiB threshold the
-large-build joins (Q5, Q7–Q9, Q17, Q18, Q21) fall back to <code 
class="docutils literal notranslate"><span 
class="pre">SortMergeJoin</span></code> while
-smaller-build joins stay hash, so the heavy queries run at roughly sort-merge 
speed
-but the suite runs end to end. Q18 completes at <strong>744.6 s</strong> where 
the same
-configuration with the fallback disabled (<code class="docutils literal 
notranslate"><span 
class="pre">hash_join_max_build_partition_bytes=0</span></code>)
-exhausts the per-slot pool and fails the job
-(<a class="reference external" 
href="https://github.com/apache/datafusion-ballista/issues/2025";>#2025</a>). 
The fallback is
-opt-in and off by default (a <code class="docutils literal notranslate"><span 
class="pre">0</span></code> budget); the 64 MiB value here is tuned to this
-cluster’s ~2.8 GB task-slot pool.</p>
-</section>
 <section id="recording-a-result">
 <h3>Recording a result<a class="headerlink" href="#recording-a-result" 
title="Link to this heading">#</a></h3>
 <ul class="simple">
@@ -955,9 +868,10 @@ cluster’s ~2.8 GB task-slot pool.</p>
 configuration this page measures — from the same commit and cluster.</p></li>
 <li><p>Prefer the figure from a <strong>full suite run</strong>, not a 
standalone single-query run: a
 long-lived executor deep into a suite is not in the same state as a freshly 
started
-one. When a query cannot complete in-suite (e.g. Q18’s OOM currently wedges the
-run), note that the remaining queries were run individually, as done here for
-Q19–Q22.</p></li>
+one, and a single-query job pays a cold-cache penalty that is large enough to 
swamp
+the effect being measured. When a query cannot complete in-suite (e.g. Q18’s 
OOM
+currently wedges the run), exclude it with <code class="docutils literal 
notranslate"><span class="pre">--skip</span> <span 
class="pre">&lt;n&gt;</span></code> so the rest of the column
+still comes from one continuous run, and measure that query 
separately.</p></li>
 <li><p>Note the <strong>row count</strong> each query returned. A fast wrong 
answer is not a result,
 and distributed execution has produced silently wrong row counts 
before.</p></li>
 <li><p>Flag any stage whose runtime is dominated by a few partitions — that is 
the
@@ -1050,7 +964,6 @@ knowing about before interpreting a number:</p>
 </li>
 <li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" 
href="#why-compare-against-comet">Why compare against Comet</a></li>
 <li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" 
href="#results">Results</a><ul class="nav section-nav flex-column">
-<li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link" 
href="#hash-join-with-a-per-partition-build-size-fallback-aqe-on-216-cores-64-partitions">Hash
 join with a per-partition build-size fallback (AQE on, 2×16 cores, 64 
partitions)</a></li>
 <li class="toc-h3 nav-item toc-entry"><a class="reference internal nav-link" 
href="#recording-a-result">Recording a result</a></li>
 </ul>
 </li>
diff --git a/searchindex.js b/searchindex.js
index ec85f4218..e421c7004 100644
--- a/searchindex.js
+++ b/searchindex.js
@@ -1 +1 @@
-Search.setIndex({"alltitles":{"AQE join behavior 
(opt-in)":[[27,"aqe-join-behavior-opt-in"]],"Adaptive Query Execution 
(AQE)":[[21,"adaptive-query-execution-aqe"]],"Adaptive Query Execution 
(Experimental)":[[50,"adaptive-query-execution-experimental"]],"Adding a 
persona":[[25,"adding-a-persona"]],"Aggregate 
Functions":[[49,"aggregate-functions"]],"Apache DataFusion 
Ballista":[[26,null]],"Apache DataFusion Ballista 0.10.0 
Changelog":[[0,null]],"Apache DataFusion Ballista 0.11.0 Changelog" [...]
\ No newline at end of file
+Search.setIndex({"alltitles":{"AQE join behavior 
(opt-in)":[[27,"aqe-join-behavior-opt-in"]],"Adaptive Query Execution 
(AQE)":[[21,"adaptive-query-execution-aqe"]],"Adaptive Query Execution 
(Experimental)":[[50,"adaptive-query-execution-experimental"]],"Adding a 
persona":[[25,"adding-a-persona"]],"Aggregate 
Functions":[[49,"aggregate-functions"]],"Apache DataFusion 
Ballista":[[26,null]],"Apache DataFusion Ballista 0.10.0 
Changelog":[[0,null]],"Apache DataFusion Ballista 0.11.0 Changelog" [...]
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to