Rich-T-kid opened a new pull request, #26250:
URL: https://github.com/apache/datafusion/pull/26250

   ## Which issue does this PR close?
   
   <!-- none; this adds reproducibility tooling. Happy to open a tracking issue 
first if preferred. -->
   
   - Closes #.
   
   ## Rationale for this change
   
   Several recent PRs that touch dictionary / `Utf8View` operator paths have had
   to answer the same question: *"at what cardinality does dictionary encoding
   stop being a win over `Utf8View`?"* There is no in-tree harness that answers
   this reproducibly — contributors have been spinning up ad-hoc scripts, each
   measuring slightly different things.
   
   This PR adds `dict_encoding_sweep`: a focused benchmark driver that generates
   two in-memory tables sharing identical values (one `Utf8View`, one
   `Dictionary<Int32, Utf8>`), runs the same SQL against each, and reports
   median/min/p25/p75 runtimes to CSV. One invocation sweeps across an NDV
   grid for a chosen operator group so the crossover point is directly visible.
   
   ## What changes are included in this PR?
   
   - `benchmarks/src/dict_encoding_sweep.rs` — harness library (deterministic
     data gen, interleaved warmup/timing loop, per-group query catalog, CSV
     writer).
   - `benchmarks/src/bin/dict_encoding_sweep.rs` — CLI driver; one invocation
     handles one `(group, rows, width, nulls, batch_size)` combination and
     sweeps across the provided `--ndvs`.
   - `benchmarks/README.md` — new *Dictionary vs Utf8View Encoding Sweep*
     section documenting operator groups, flags, and CSV schema.
   
   Nothing under `datafusion/` is touched.
   
   ## What is the testing strategy for this PR?
   
   The sweep binary is itself the artifact — a smoke run (`--rows 100000 --ndvs
   10,1000 --iters 3 --warmups 1`) completes end-to-end and writes a valid CSV.
   No new unit tests are added; the harness is a self-contained reproduction
   tool rather than a code path exercised by production queries. `cargo fmt
   --all --check` and `cargo clippy -p datafusion-benchmarks --lib --bins
   --all-features -- -D warnings` both pass on the new files.
   
   ## Are there any user-facing changes?
   
   No. New files under `benchmarks/`.
   
   ## Results
   
   Numbers below come from running the harness on this branch, 2026-10-12, with
   `--iters 15 --warmups 3 --dict-chunk 100000 --ndvs 
10,100,500,1000,4000,8192`.
   Cells are **`dict median / view median`** — values `< 1.00` mean dictionary
   is faster, `> 1.00` means `Utf8View` wins. Variance on this machine is
   roughly ±20 %; treat differences inside that band as noise. Full CSVs are
   reproducible from the commands in `benchmarks/README.md`.
   
   ### filter — 1,000,000 rows
   
   | query \ ndv        | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |--------------------|------|------|------|------|------|------|
   | filter_1pct_group  | 0.43 | 0.54 | 0.24 | 0.29 | 0.53 | 1.05 |
   | filter_eq          | 0.29 | 0.49 | 0.63 | 0.72 | 1.45 | 2.41 |
   | filter_gt          | 0.36 | 0.65 | 0.79 | 0.92 | 1.82 | 3.05 |
   | filter_in10        | 0.09 | 0.10 | 0.18 | 0.25 | 0.62 | 1.13 |
   | filter_like_prefix | 0.26 | 0.30 | 0.30 | 0.35 | 0.60 | 0.95 |
   | filter_ne          | 0.30 | 0.49 | 0.62 | 0.74 | 1.41 | 2.37 |
   
   ### filter — 5,000,000 rows
   
   | query \ ndv        | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |--------------------|------|------|------|------|------|------|
   | filter_1pct_group  | 0.41 | 0.46 | 0.24 | 0.28 | 0.53 | 1.01 |
   | filter_eq          | 0.28 | 0.39 | 0.57 | 0.73 | 1.41 | 2.32 |
   | filter_gt          | 0.34 | 0.54 | 0.75 | 0.94 | 1.75 | 3.01 |
   | filter_in10        | 0.09 | 0.10 | 0.18 | 0.25 | 0.62 | 1.11 |
   | filter_like_prefix | 0.25 | 0.31 | 0.30 | 0.35 | 0.59 | 0.93 |
   | filter_ne          | 0.29 | 0.41 | 0.60 | 0.73 | 1.40 | 2.36 |
   
   ### aggregation — 1,000,000 rows
   
   | query \ ndv          | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |----------------------|------|------|------|------|------|------|
   | agg_count_distinct_k | 0.70 | 0.78 | 0.71 | 0.71 | 0.79 | 0.91 |
   | agg_group_count_k    | 0.75 | 0.81 | 0.75 | 0.74 | 0.79 | 0.94 |
   | agg_group_count_kw   | 0.70 | 0.72 | 0.69 | 0.71 | 0.82 | 0.90 |
   | agg_group_sum_v_k    | 0.76 | 0.83 | 0.75 | 0.74 | 0.80 | 0.92 |
   | agg_having_k         | 0.75 | 0.81 | 0.76 | 0.74 | 0.79 | 0.94 |
   
   ### aggregation — 5,000,000 rows
   
   | query \ ndv          | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |----------------------|------|------|------|------|------|------|
   | agg_count_distinct_k | 0.70 | 0.79 | 0.71 | 0.71 | 0.77 | 0.89 |
   | agg_group_count_k    | 0.75 | 0.81 | 0.73 | 0.74 | 0.78 | 0.92 |
   | agg_group_count_kw   | 0.70 | 0.72 | 0.69 | 0.71 | 0.80 | 0.86 |
   | agg_group_sum_v_k    | 0.75 | 0.82 | 0.75 | 0.74 | 0.77 | 0.91 |
   | agg_having_k         | 0.75 | 0.81 | 0.74 | 0.73 | 0.78 | 0.92 |
   
   ### sort — 1,000,000 rows
   
   | query \ ndv       | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |-------------------|------|------|------|------|------|------|
   | sort_k            | 0.50 | 0.58 | 0.61 | 0.64 | 0.90 | 1.36 |
   | sort_k_desc       | 0.50 | 0.59 | 0.65 | 0.67 | 0.95 | 1.41 |
   | sort_k_limit_1000 | 0.35 | 0.65 | 0.80 | 1.12 | 1.46 | 1.91 |
   | sort_kw           | 1.02 | 1.75 | 1.71 | 1.65 | 1.60 | 1.66 |
   | sort_v_by_k       | 0.54 | 0.50 | 0.71 | 0.73 | 1.11 | 1.87 |
   
   ### sort — 5,000,000 rows
   
   | query \ ndv       | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |-------------------|------|------|------|------|------|------|
   | sort_k            | 0.51 | 0.74 | 0.72 | 0.74 | 1.11 | 1.86 |
   | sort_k_desc       | 0.50 | 0.74 | 0.73 | 0.75 | 1.15 | 1.89 |
   | sort_k_limit_1000 | 0.31 | 0.57 | 0.76 | 0.90 | 1.79 | 3.68 |
   | sort_kw           | 1.02 | 3.16 | 2.73 | 2.63 | 2.60 | 2.60 |
   | sort_v_by_k       | 0.56 | 1.15 | 0.99 | 0.95 | 1.50 | 2.81 |
   
   ### project — 1,000,000 rows
   
   | query \ ndv    | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |----------------|------|------|------|------|------|------|
   | proj_case_like | 0.40 | 0.46 | 0.46 | 0.51 | 0.73 | 0.93 |
   | proj_concat    | 0.91 | 0.92 | 0.92 | 0.91 | 0.92 | 0.94 |
   | proj_length    | 0.03 | 0.03 | 0.04 | 0.06 | 0.15 | 0.34 |
   | proj_substr    | 1.71 | 1.73 | 1.71 | 1.75 | 1.75 | 1.74 |
   | proj_upper     | 0.01 | 0.01 | 0.01 | 0.02 | 0.04 | 0.09 |
   
   ### project — 5,000,000 rows
   
   | query \ ndv    | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |----------------|------|------|------|------|------|------|
   | proj_case_like | 0.42 | 0.47 | 0.47 | 0.52 | 0.77 | 0.99 |
   | proj_concat    | 0.92 | 0.92 | 0.92 | 0.90 | 0.92 | 0.92 |
   | proj_length    | 0.03 | 0.03 | 0.04 | 0.07 | 0.17 | 0.37 |
   | proj_substr    | 1.75 | 1.74 | 1.74 | 1.74 | 1.74 | 1.75 |
   | proj_upper     | 0.01 | 0.01 | 0.01 | 0.01 | 0.04 | 0.08 |
   
   ### join — 1,000,000 rows
   
   | query \ ndv        | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |--------------------|------|------|------|------|------|------|
   | join_anti_half     | 0.98 | 1.00 | 0.97 | 0.97 | 1.00 | 1.06 |
   | join_inner         | 0.94 | 1.05 | 1.00 | 0.99 | 1.05 | 1.24 |
   | join_inner_project | 0.94 | 0.98 | 1.00 | 0.96 | 1.04 | 1.23 |
   | join_left          | 0.95 | 1.02 | 0.95 | 0.95 | 1.05 | 1.24 |
   | join_semi          | 0.94 | 1.00 | 0.98 | 0.96 | 1.06 | 1.21 |
   
   ### join — 5,000,000 rows
   
   | query \ ndv        | 10   | 100  | 500  | 1000 | 4000 | 8192 |
   |--------------------|------|------|------|------|------|------|
   | join_anti_half     | 0.98 | 1.01 | 0.96 | 0.98 | 0.99 | 1.05 |
   | join_inner         | 0.97 | 1.04 | 1.00 | 0.96 | 1.06 | 1.26 |
   | join_inner_project | 0.93 | 1.01 | 0.96 | 0.96 | 1.05 | 1.21 |
   | join_left          | 0.98 | 1.00 | 0.98 | 0.96 | 1.06 | 1.24 |
   | join_semi          | 0.97 | 1.00 | 0.99 | 0.99 | 1.05 | 1.21 |
   
   Headline takeaways consistent across both row counts:
   
   - **Filter / projection / aggregation at low NDV**: dictionary dominates
     (ratios 0.03–0.50); the crossover against `Utf8View` sits around NDV ≈ 1k.
   - **Sort**: dictionary wins at low NDV but loses from NDV ≈ 4k upward; the
     `sort_kw` ties-breaker column exposes a large regression (~1.7–3×).
   - **Join**: nearly a wash at low NDV; mild `Utf8View` edge (~1.05–1.26×)
     past NDV 4k.
   - **proj_substr**: `Utf8View` is consistently faster regardless of NDV,
     because `substr` on a view can skip materialization.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to