Skip to content

perf: route probe rows to ArrayMap build partitions in the merged hash join filter - #27091

Merged
jayzhan211 merged 3 commits into
apache:mainfrom
adriangb:routed-lookup-array-map
Nov 11, 2026
Merged

jayzhan211 merged 3 commits into
apache:mainfrom
adriangb:routed-lookup-array-map

Conversation

@adriangb

@adriangb adriangb commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Note

Stacked on #27090, which adds the benchmark queries used below. Review only the last commit, perf: route probe rows to ArrayMap build partitions in the merged filter.

Rationale for this change

A Partitioned hash join on dense integer keys runs much slower with Parquet filter pushdown on than with it off. On TPC-H SF10 the hj Q26 join takes 93.5 ms with pushdown_filters=true, against 50.0 ms with it off. A similar join on sparse keys (Q27) does not slow down this way.

The cause is the filter the join pushes into its probe-side scan. Each build partition of a dense-key join builds an ArrayMap. The routed lookup from #26249 accepts only hash tables, so these joins fall back to a CASE with one branch per partition. The scan evaluates that CASE on every row.

What changes are included in this PR?

The routed lookup now probes an ArrayMap partition with the key values of the rows routed to it, because an ArrayMap is keyed by value, not by hash. Every non-empty partition can now merge into the routed lookup. The CASE fallback remains only for canceled partitions. A follow-up PR removes it.

What is the testing strategy for this PR?

routed_lookup_fuzz now builds an ArrayMap for about half of its partitions. It compares the routed lookup with one lookup over the whole build side. All datafusion-physical-plan tests and all sqllogictests pass.

hj on TPC-H SF10, 16 partitions, median of 10 iterations:

Query pushdown_filters main + #27090 This PR
Q26 (dense keys) true 93.5 ms 44.7 ms
Q26 (dense keys) false 50.0 ms 48.2 ms
Q27 (sparse keys) true 59.2 ms 57.3 ms
Q27 (sparse keys) false 54.5 ms 55.6 ms

Only Q26 with pushdown on changes. Its probe filter goes from CASE hash_repartition % 16 WHEN 0 THEN ... hash_lookup ... to one hash_lookup.

Are there any user-facing changes?

No API changes. A Partitioned hash join on dense integer keys runs faster when Parquet filter pushdown is on.

🤖 Generated with Claude Code

@github-actions github-actions Bot added the physical-plan Changes to the physical-plan crate label Nov 4, 2026
A `Partitioned` hash join merges its partitions' build maps into one routed
`hash_lookup` filter. The routed lookup accepted only hash tables, so a join
whose partitions built an `ArrayMap` (dense integer keys) fell back to a
`CASE` over one filter per partition.

The routed lookup now probes an `ArrayMap` partition with the key values of
the rows routed to it, because an `ArrayMap` is keyed by value, not hash.
Every non-empty partition can now merge. The `CASE` fallback remains only
for canceled partitions. The routed lookup fuzz test now builds an
`ArrayMap` for about half of the partitions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@adriangb
adriangb force-pushed the routed-lookup-array-map branch from c133310 to 97db09b Compare November 4, 2026 21:56
@adriangb

adriangb commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run benchmarks

@adriangb

adriangb commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run benchmark hj

@adriangb

adriangb commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run benchmark tpch10

@adriangbot

Copy link
Copy Markdown

Benchmark for this request failed before finishing (Kubernetes reason: BackoffLimitExceeded).

Benchmarks requested: clickbench_partitioned

Runner log (last 40 lines)
2026-11-04T21:59:41.735347Z  INFO runner starting benchmark runner bench_type=Datafusion, pr_url=https://github.com/apache/datafusion/pull/27091, benchmarks=clickbench_partitioned
2026-11-04T21:59:41.796415Z  INFO benchmark_controller::runner::bench_datafusion === Cloning PR branch ===
2026-11-04T21:59:41.796437Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-branch"], cwd="/"
2026-11-04T21:59:46.805513Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["fetch", "origin", "refs/pull/27091/head:routed-lookup-array-map", "main"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:51.807634Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["checkout", "routed-lookup-array-map"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:56.809372Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["merge-base", "HEAD", "origin/main"], cwd="/workspace/datafusion-branch"
2026-11-04T22:00:01.811700Z  INFO benchmark_controller::runner::bench_datafusion === Cloning merge-base ===
2026-11-04T22:00:01.811718Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-base"], cwd="/"
2026-11-04T22:00:06.813425Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["-c", "advice.detachedHead=false", "checkout", "70f2ed01b8392127fa0eb4f1fb5e57869c42ecfa"], cwd="/workspace/datafusion-base"
2026-11-04T22:00:11.815288Z  INFO benchmark_controller::runner::shell running command cmd=rustc, args=["--version"], cwd="/"
2026-11-04T22:00:16.817778Z  INFO benchmark_controller::runner::shell running command cmd=cargo, args=["metadata", "--no-deps", "--format-version", "1"], cwd="/workspace/datafusion-branch/benchmarks"
2026-11-04T22:00:21.822699Z  INFO benchmark_controller::runner::bench_datafusion === Compiling dfbench for PR branch and merge-base in parallel ===
2026-11-04T22:00:21.849206Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-branch"
2026-11-04T22:00:26.851805Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-base"
2026-11-04T22:00:31.853641Z  INFO benchmark_controller::runner::controller_client post_comment _repo=apache/datafusion, _pr_number=27091, job_id=4504
2026-11-04T22:01:47.136217Z ERROR runner benchmark failed error=send request: error sending request for url (http://benchmark-controller.benchmarking.svc.cluster.local:8080/jobs/4504/comment): client error (Connect): tcp connect error: Connection refused (os error 111)
Kubernetes message
Job has reached the specified backoff limit

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

Benchmark for this request failed before finishing (Kubernetes reason: BackoffLimitExceeded).

Benchmarks requested: tpch

Runner log (last 40 lines)
2026-11-04T21:59:09.129846Z  INFO runner starting benchmark runner bench_type=Datafusion, pr_url=https://github.com/apache/datafusion/pull/27091, benchmarks=tpch
2026-11-04T21:59:09.189790Z  INFO benchmark_controller::runner::bench_datafusion === Cloning PR branch ===
2026-11-04T21:59:09.189811Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-branch"], cwd="/"
2026-11-04T21:59:19.202258Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["fetch", "origin", "refs/pull/27091/head:routed-lookup-array-map", "main"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:24.204627Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["checkout", "routed-lookup-array-map"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:29.206633Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["merge-base", "HEAD", "origin/main"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:34.207919Z  INFO benchmark_controller::runner::bench_datafusion === Cloning merge-base ===
2026-11-04T21:59:34.207935Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-base"], cwd="/"
2026-11-04T21:59:39.209873Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["-c", "advice.detachedHead=false", "checkout", "70f2ed01b8392127fa0eb4f1fb5e57869c42ecfa"], cwd="/workspace/datafusion-base"
2026-11-04T21:59:44.212744Z  INFO benchmark_controller::runner::shell running command cmd=rustc, args=["--version"], cwd="/"
2026-11-04T21:59:49.215075Z  INFO benchmark_controller::runner::shell running command cmd=cargo, args=["metadata", "--no-deps", "--format-version", "1"], cwd="/workspace/datafusion-branch/benchmarks"
2026-11-04T21:59:54.220379Z  INFO benchmark_controller::runner::bench_datafusion === Compiling dfbench for PR branch and merge-base in parallel ===
2026-11-04T21:59:54.244555Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:59.246746Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-base"
2026-11-04T22:00:04.248826Z  INFO benchmark_controller::runner::controller_client post_comment _repo=apache/datafusion, _pr_number=27091, job_id=4506
2026-11-04T22:01:19.533728Z ERROR runner benchmark failed error=send request: error sending request for url (http://benchmark-controller.benchmarking.svc.cluster.local:8080/jobs/4506/comment): client error (Connect): tcp connect error: Connection refused (os error 111)
Kubernetes message
Job has reached the specified backoff limit

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

Benchmark for this request failed before finishing (Kubernetes reason: BackoffLimitExceeded).

Benchmarks requested: hj

Runner log (last 40 lines)
2026-11-04T21:59:20.867722Z  INFO runner starting benchmark runner bench_type=Datafusion, pr_url=https://github.com/apache/datafusion/pull/27091, benchmarks=hj
2026-11-04T21:59:20.926454Z  INFO benchmark_controller::runner::bench_datafusion === Cloning PR branch ===
2026-11-04T21:59:20.926474Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-branch"], cwd="/"
2026-11-04T21:59:30.936941Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["fetch", "origin", "refs/pull/27091/head:routed-lookup-array-map", "main"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:35.938599Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["checkout", "routed-lookup-array-map"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:40.941362Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["merge-base", "HEAD", "origin/main"], cwd="/workspace/datafusion-branch"
2026-11-04T21:59:45.943668Z  INFO benchmark_controller::runner::bench_datafusion === Cloning merge-base ===
2026-11-04T21:59:45.943686Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["clone", "--depth=200", "https://github.com/apache/datafusion.git", "/workspace/datafusion-base"], cwd="/"
2026-11-04T21:59:50.945901Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["-c", "advice.detachedHead=false", "checkout", "70f2ed01b8392127fa0eb4f1fb5e57869c42ecfa"], cwd="/workspace/datafusion-base"
2026-11-04T21:59:55.947466Z  INFO benchmark_controller::runner::shell running command cmd=rustc, args=["--version"], cwd="/"
2026-11-04T22:00:00.949599Z  INFO benchmark_controller::runner::shell running command cmd=cargo, args=["metadata", "--no-deps", "--format-version", "1"], cwd="/workspace/datafusion-branch/benchmarks"
2026-11-04T22:00:05.954100Z  INFO benchmark_controller::runner::bench_datafusion === Compiling dfbench for PR branch and merge-base in parallel ===
2026-11-04T22:00:05.980698Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-branch"
2026-11-04T22:00:10.983114Z  INFO benchmark_controller::runner::shell running command cmd=git, args=["rev-parse", "HEAD"], cwd="/workspace/datafusion-base"
2026-11-04T22:00:15.985457Z  INFO benchmark_controller::runner::controller_client post_comment _repo=apache/datafusion, _pr_number=27091, job_id=4507
2026-11-04T22:01:31.284673Z ERROR runner benchmark failed error=send request: error sending request for url (http://benchmark-controller.benchmarking.svc.cluster.local:8080/jobs/4507/comment): client error (Connect): tcp connect error: Connection refused (os error 111)
Kubernetes message
Job has reached the specified backoff limit

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6643153930-4505-4qmwm 6.12.105+ #1 SMP Sat Sep 19 07:55:25 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing routed-lookup-array-map (97db09b) to 70f2ed0 (merge-base) diff

Run configuration
run benchmark tpcds

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6643162806-4508-42ql8 6.12.105+ #1 SMP Sat Sep 19 07:55:25 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing routed-lookup-array-map (97db09b) to 70f2ed0 (merge-base) diff

Run configuration
run benchmark tpch10

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing routed-lookup-array-map (97db09b) to 70f2ed0 (merge-base) diff

Run configuration
run benchmark tpcds
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and routed-lookup-array-map
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ routed-lookup-array-map ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │    5.28 ms │                 5.33 ms │     no change │
│ QQuery 2  │   78.71 ms │                79.74 ms │     no change │
│ QQuery 3  │   28.77 ms │                28.58 ms │     no change │
│ QQuery 4  │  610.77 ms │               644.24 ms │  1.05x slower │
│ QQuery 5  │   49.27 ms │                49.11 ms │     no change │
│ QQuery 6  │   34.91 ms │                34.69 ms │     no change │
│ QQuery 7  │   72.35 ms │                70.69 ms │     no change │
│ QQuery 8  │   36.28 ms │                36.05 ms │     no change │
│ QQuery 9  │   51.83 ms │                51.52 ms │     no change │
│ QQuery 10 │   60.43 ms │                59.63 ms │     no change │
│ QQuery 11 │  346.62 ms │               345.53 ms │     no change │
│ QQuery 12 │   28.82 ms │                28.73 ms │     no change │
│ QQuery 13 │  112.62 ms │               112.07 ms │     no change │
│ QQuery 14 │  374.02 ms │               375.02 ms │     no change │
│ QQuery 15 │   53.02 ms │                54.10 ms │     no change │
│ QQuery 16 │    6.11 ms │                 6.09 ms │     no change │
│ QQuery 17 │   74.05 ms │                74.86 ms │     no change │
│ QQuery 18 │  104.77 ms │               103.48 ms │     no change │
│ QQuery 19 │   40.70 ms │                40.98 ms │     no change │
│ QQuery 20 │   34.95 ms │                35.43 ms │     no change │
│ QQuery 21 │   16.84 ms │                16.88 ms │     no change │
│ QQuery 22 │   63.41 ms │                62.66 ms │     no change │
│ QQuery 23 │  288.49 ms │               288.83 ms │     no change │
│ QQuery 24 │  190.60 ms │               194.14 ms │     no change │
│ QQuery 25 │  103.52 ms │               104.02 ms │     no change │
│ QQuery 26 │   44.85 ms │                45.30 ms │     no change │
│ QQuery 27 │    5.75 ms │                 5.79 ms │     no change │
│ QQuery 28 │   56.05 ms │                60.49 ms │  1.08x slower │
│ QQuery 29 │   90.86 ms │                91.55 ms │     no change │
│ QQuery 30 │   31.95 ms │                31.74 ms │     no change │
│ QQuery 31 │  106.67 ms │               106.75 ms │     no change │
│ QQuery 32 │   19.84 ms │                20.57 ms │     no change │
│ QQuery 33 │   37.60 ms │                37.91 ms │     no change │
│ QQuery 34 │    9.74 ms │                10.09 ms │     no change │
│ QQuery 35 │   70.57 ms │                71.61 ms │     no change │
│ QQuery 36 │    5.40 ms │                 5.40 ms │     no change │
│ QQuery 37 │    6.57 ms │                 6.71 ms │     no change │
│ QQuery 38 │   60.21 ms │                60.45 ms │     no change │
│ QQuery 39 │   71.07 ms │                70.39 ms │     no change │
│ QQuery 40 │   22.50 ms │                23.09 ms │     no change │
│ QQuery 41 │   12.12 ms │                12.05 ms │     no change │
│ QQuery 42 │   23.52 ms │                23.52 ms │     no change │
│ QQuery 43 │    4.49 ms │                 4.47 ms │     no change │
│ QQuery 44 │    8.41 ms │                 8.49 ms │     no change │
│ QQuery 45 │   36.18 ms │                35.77 ms │     no change │
│ QQuery 46 │   11.40 ms │                11.67 ms │     no change │
│ QQuery 47 │  215.52 ms │               222.78 ms │     no change │
│ QQuery 48 │   91.00 ms │                90.67 ms │     no change │
│ QQuery 49 │   69.33 ms │                69.23 ms │     no change │
│ QQuery 50 │   56.11 ms │                57.00 ms │     no change │
│ QQuery 51 │   95.00 ms │                93.56 ms │     no change │
│ QQuery 52 │   23.63 ms │                23.80 ms │     no change │
│ QQuery 53 │   28.94 ms │                28.94 ms │     no change │
│ QQuery 54 │   53.03 ms │                52.64 ms │     no change │
│ QQuery 55 │   23.56 ms │                23.48 ms │     no change │
│ QQuery 56 │   38.68 ms │                38.05 ms │     no change │
│ QQuery 57 │  166.27 ms │               167.16 ms │     no change │
│ QQuery 58 │  104.56 ms │               106.12 ms │     no change │
│ QQuery 59 │  113.06 ms │               114.68 ms │     no change │
│ QQuery 60 │   38.98 ms │                39.24 ms │     no change │
│ QQuery 61 │    9.05 ms │                 9.19 ms │     no change │
│ QQuery 62 │   42.93 ms │                43.67 ms │     no change │
│ QQuery 63 │   29.35 ms │                29.25 ms │     no change │
│ QQuery 64 │  345.73 ms │               348.12 ms │     no change │
│ QQuery 65 │   73.61 ms │                73.18 ms │     no change │
│ QQuery 66 │   71.44 ms │                72.16 ms │     no change │
│ QQuery 67 │  248.99 ms │               248.55 ms │     no change │
│ QQuery 68 │   11.38 ms │                11.43 ms │     no change │
│ QQuery 69 │   54.78 ms │                55.11 ms │     no change │
│ QQuery 70 │  101.76 ms │               102.78 ms │     no change │
│ QQuery 71 │   34.55 ms │                34.66 ms │     no change │
│ QQuery 72 │ 1625.26 ms │              1509.84 ms │ +1.08x faster │
│ QQuery 73 │   10.09 ms │                 9.54 ms │ +1.06x faster │
│ QQuery 74 │  188.51 ms │               186.74 ms │     no change │
│ QQuery 75 │  135.87 ms │               136.87 ms │     no change │
│ QQuery 76 │   34.00 ms │                34.03 ms │     no change │
│ QQuery 77 │   58.74 ms │                58.90 ms │     no change │
│ QQuery 78 │  269.46 ms │               262.12 ms │     no change │
│ QQuery 79 │   66.63 ms │                65.76 ms │     no change │
│ QQuery 80 │   93.73 ms │                93.31 ms │     no change │
│ QQuery 81 │   25.86 ms │                25.17 ms │     no change │
│ QQuery 82 │   16.70 ms │                15.97 ms │     no change │
│ QQuery 83 │   32.99 ms │                31.54 ms │     no change │
│ QQuery 84 │   30.02 ms │                28.88 ms │     no change │
│ QQuery 85 │   97.78 ms │                97.79 ms │     no change │
│ QQuery 86 │   25.83 ms │                24.77 ms │     no change │
│ QQuery 87 │   62.07 ms │                59.38 ms │     no change │
│ QQuery 88 │   59.64 ms │                58.38 ms │     no change │
│ QQuery 89 │   35.77 ms │                35.08 ms │     no change │
│ QQuery 90 │   16.56 ms │                15.72 ms │ +1.05x faster │
│ QQuery 91 │   40.27 ms │                39.65 ms │     no change │
│ QQuery 92 │   30.24 ms │                28.67 ms │ +1.05x faster │
│ QQuery 93 │   50.07 ms │                48.50 ms │     no change │
│ QQuery 94 │   38.66 ms │                37.56 ms │     no change │
│ QQuery 95 │   81.07 ms │                78.58 ms │     no change │
│ QQuery 96 │   24.12 ms │                23.35 ms │     no change │
│ QQuery 97 │   51.79 ms │                49.56 ms │     no change │
│ QQuery 98 │   43.51 ms │                42.17 ms │     no change │
│ QQuery 99 │   64.91 ms │                64.83 ms │     no change │
└───────────┴────────────┴─────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                      ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                      │ 9054.29ms │
│ Total Time (routed-lookup-array-map)   │ 8964.31ms │
│ Average Time (HEAD)                    │   91.46ms │
│ Average Time (routed-lookup-array-map) │   90.55ms │
│ Queries Faster                         │         4 │
│ Queries Slower                         │         2 │
│ Queries with No Change                 │        93 │
│ Queries with Failure                   │         0 │
└────────────────────────────────────────┴───────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and routed-lookup-array-map
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃               routed-lookup-array-map ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │           5.28 / 5.97 ±1.10 / 8.16 ms │           5.33 / 5.95 ±1.02 / 7.97 ms │     no change │
│ QQuery 2  │        78.71 / 79.19 ±0.24 / 79.35 ms │        79.74 / 80.56 ±0.54 / 81.32 ms │     no change │
│ QQuery 3  │        28.77 / 28.91 ±0.16 / 29.23 ms │        28.58 / 28.81 ±0.13 / 28.92 ms │     no change │
│ QQuery 4  │     610.77 / 622.88 ±8.71 / 637.91 ms │     644.24 / 647.88 ±3.65 / 654.48 ms │     no change │
│ QQuery 5  │        49.27 / 49.71 ±0.27 / 49.95 ms │        49.11 / 50.70 ±1.60 / 52.99 ms │     no change │
│ QQuery 6  │        34.91 / 37.14 ±3.37 / 43.86 ms │        34.69 / 35.43 ±0.48 / 36.13 ms │     no change │
│ QQuery 7  │        72.35 / 73.32 ±0.93 / 74.99 ms │        70.69 / 71.72 ±0.58 / 72.34 ms │     no change │
│ QQuery 8  │        36.28 / 36.48 ±0.19 / 36.84 ms │        36.05 / 36.44 ±0.35 / 37.08 ms │     no change │
│ QQuery 9  │        51.83 / 52.81 ±1.30 / 55.37 ms │        51.52 / 51.75 ±0.34 / 52.43 ms │     no change │
│ QQuery 10 │        60.43 / 61.99 ±2.17 / 66.30 ms │        59.63 / 60.04 ±0.22 / 60.27 ms │     no change │
│ QQuery 11 │     346.62 / 351.17 ±3.98 / 356.93 ms │     345.53 / 348.47 ±2.53 / 351.70 ms │     no change │
│ QQuery 12 │        28.82 / 29.87 ±1.33 / 32.36 ms │        28.73 / 29.26 ±0.45 / 29.81 ms │     no change │
│ QQuery 13 │     112.62 / 113.28 ±0.50 / 114.16 ms │     112.07 / 113.24 ±0.62 / 113.81 ms │     no change │
│ QQuery 14 │     374.02 / 377.81 ±2.82 / 382.03 ms │     375.02 / 377.60 ±2.85 / 382.78 ms │     no change │
│ QQuery 15 │        53.02 / 53.58 ±0.51 / 54.37 ms │        54.10 / 54.62 ±0.52 / 55.57 ms │     no change │
│ QQuery 16 │           6.11 / 6.32 ±0.19 / 6.66 ms │           6.09 / 6.24 ±0.13 / 6.46 ms │     no change │
│ QQuery 17 │        74.05 / 76.03 ±1.48 / 78.51 ms │        74.86 / 75.92 ±1.19 / 78.23 ms │     no change │
│ QQuery 18 │     104.77 / 105.34 ±0.41 / 105.93 ms │     103.48 / 105.07 ±1.92 / 108.75 ms │     no change │
│ QQuery 19 │        40.70 / 40.83 ±0.12 / 41.07 ms │        40.98 / 41.99 ±1.34 / 44.63 ms │     no change │
│ QQuery 20 │        34.95 / 35.32 ±0.43 / 36.14 ms │        35.43 / 36.16 ±0.60 / 37.07 ms │     no change │
│ QQuery 21 │        16.84 / 17.09 ±0.21 / 17.42 ms │        16.88 / 17.13 ±0.31 / 17.73 ms │     no change │
│ QQuery 22 │        63.41 / 64.14 ±0.77 / 65.54 ms │        62.66 / 63.60 ±0.93 / 65.03 ms │     no change │
│ QQuery 23 │     288.49 / 292.32 ±6.44 / 305.15 ms │     288.83 / 296.39 ±7.05 / 309.04 ms │     no change │
│ QQuery 24 │     190.60 / 193.90 ±3.91 / 201.38 ms │     194.14 / 196.06 ±1.89 / 199.53 ms │     no change │
│ QQuery 25 │     103.52 / 108.57 ±6.71 / 121.64 ms │     104.02 / 105.58 ±1.39 / 107.45 ms │     no change │
│ QQuery 26 │        44.85 / 45.34 ±0.45 / 46.20 ms │        45.30 / 45.56 ±0.24 / 45.95 ms │     no change │
│ QQuery 27 │           5.75 / 5.98 ±0.17 / 6.24 ms │           5.79 / 5.89 ±0.16 / 6.21 ms │     no change │
│ QQuery 28 │        56.05 / 60.09 ±2.06 / 61.51 ms │        60.49 / 61.24 ±0.48 / 61.80 ms │     no change │
│ QQuery 29 │        90.86 / 92.96 ±1.65 / 95.39 ms │       91.55 / 95.03 ±6.00 / 107.00 ms │     no change │
│ QQuery 30 │        31.95 / 32.18 ±0.17 / 32.43 ms │        31.74 / 32.13 ±0.34 / 32.76 ms │     no change │
│ QQuery 31 │     106.67 / 107.09 ±0.28 / 107.40 ms │     106.75 / 107.64 ±0.76 / 108.60 ms │     no change │
│ QQuery 32 │        19.84 / 21.02 ±1.55 / 24.02 ms │        20.57 / 21.04 ±0.57 / 22.11 ms │     no change │
│ QQuery 33 │        37.60 / 38.40 ±0.91 / 39.90 ms │        37.91 / 38.39 ±0.51 / 39.34 ms │     no change │
│ QQuery 34 │         9.74 / 10.00 ±0.19 / 10.33 ms │        10.09 / 10.40 ±0.35 / 11.07 ms │     no change │
│ QQuery 35 │        70.57 / 70.76 ±0.17 / 70.98 ms │        71.61 / 72.77 ±0.68 / 73.52 ms │     no change │
│ QQuery 36 │           5.40 / 5.58 ±0.21 / 5.98 ms │           5.40 / 5.56 ±0.26 / 6.08 ms │     no change │
│ QQuery 37 │           6.57 / 7.10 ±0.92 / 8.95 ms │           6.71 / 6.86 ±0.10 / 7.03 ms │     no change │
│ QQuery 38 │        60.21 / 60.74 ±0.64 / 61.96 ms │        60.45 / 62.27 ±2.94 / 68.13 ms │     no change │
│ QQuery 39 │        71.07 / 73.92 ±4.69 / 83.26 ms │        70.39 / 72.13 ±0.95 / 73.29 ms │     no change │
│ QQuery 40 │        22.50 / 22.78 ±0.41 / 23.60 ms │        23.09 / 23.67 ±0.62 / 24.61 ms │     no change │
│ QQuery 41 │        12.12 / 12.24 ±0.09 / 12.37 ms │        12.05 / 12.20 ±0.12 / 12.38 ms │     no change │
│ QQuery 42 │        23.52 / 23.75 ±0.26 / 24.25 ms │        23.52 / 24.28 ±1.15 / 26.57 ms │     no change │
│ QQuery 43 │           4.49 / 5.10 ±0.85 / 6.76 ms │           4.47 / 4.64 ±0.21 / 5.04 ms │ +1.10x faster │
│ QQuery 44 │           8.41 / 8.52 ±0.10 / 8.70 ms │           8.49 / 8.64 ±0.16 / 8.91 ms │     no change │
│ QQuery 45 │        36.18 / 37.08 ±0.56 / 37.79 ms │        35.77 / 37.46 ±0.92 / 38.15 ms │     no change │
│ QQuery 46 │        11.40 / 11.60 ±0.15 / 11.79 ms │        11.67 / 13.00 ±1.58 / 15.91 ms │  1.12x slower │
│ QQuery 47 │     215.52 / 219.91 ±4.32 / 227.74 ms │     222.78 / 227.36 ±3.90 / 232.48 ms │     no change │
│ QQuery 48 │        91.00 / 91.22 ±0.21 / 91.55 ms │        90.67 / 91.48 ±0.62 / 92.33 ms │     no change │
│ QQuery 49 │        69.33 / 70.07 ±0.88 / 71.80 ms │        69.23 / 69.83 ±0.68 / 71.09 ms │     no change │
│ QQuery 50 │        56.11 / 58.55 ±3.89 / 66.28 ms │        57.00 / 59.40 ±3.72 / 66.76 ms │     no change │
│ QQuery 51 │        95.00 / 95.52 ±0.37 / 95.88 ms │        93.56 / 94.53 ±1.05 / 96.52 ms │     no change │
│ QQuery 52 │        23.63 / 24.14 ±0.39 / 24.75 ms │        23.80 / 23.91 ±0.09 / 24.03 ms │     no change │
│ QQuery 53 │        28.94 / 29.61 ±0.51 / 30.14 ms │        28.94 / 29.58 ±1.03 / 31.62 ms │     no change │
│ QQuery 54 │        53.03 / 55.49 ±3.88 / 63.19 ms │        52.64 / 53.35 ±0.57 / 54.25 ms │     no change │
│ QQuery 55 │        23.56 / 24.18 ±0.42 / 24.86 ms │        23.48 / 23.54 ±0.04 / 23.59 ms │     no change │
│ QQuery 56 │        38.68 / 39.13 ±0.23 / 39.35 ms │        38.05 / 38.20 ±0.14 / 38.44 ms │     no change │
│ QQuery 57 │     166.27 / 169.83 ±5.02 / 179.70 ms │     167.16 / 168.61 ±2.16 / 172.89 ms │     no change │
│ QQuery 58 │     104.56 / 105.28 ±0.46 / 105.90 ms │     106.12 / 106.98 ±0.53 / 107.60 ms │     no change │
│ QQuery 59 │     113.06 / 113.99 ±0.60 / 114.64 ms │     114.68 / 115.90 ±2.03 / 119.91 ms │     no change │
│ QQuery 60 │        38.98 / 39.29 ±0.38 / 39.99 ms │        39.24 / 39.71 ±0.37 / 40.26 ms │     no change │
│ QQuery 61 │          9.05 / 9.72 ±1.09 / 11.88 ms │           9.19 / 9.34 ±0.18 / 9.68 ms │     no change │
│ QQuery 62 │        42.93 / 43.33 ±0.25 / 43.62 ms │        43.67 / 43.83 ±0.09 / 43.90 ms │     no change │
│ QQuery 63 │        29.35 / 30.90 ±2.58 / 36.03 ms │        29.25 / 31.00 ±2.80 / 36.54 ms │     no change │
│ QQuery 64 │     345.73 / 350.21 ±3.52 / 355.02 ms │     348.12 / 349.33 ±1.39 / 351.68 ms │     no change │
│ QQuery 65 │        73.61 / 75.84 ±3.60 / 82.99 ms │        73.18 / 76.62 ±4.32 / 84.90 ms │     no change │
│ QQuery 66 │        71.44 / 72.52 ±0.56 / 73.08 ms │        72.16 / 72.45 ±0.27 / 72.88 ms │     no change │
│ QQuery 67 │     248.99 / 257.12 ±9.27 / 274.83 ms │     248.55 / 255.48 ±7.24 / 268.73 ms │     no change │
│ QQuery 68 │        11.38 / 11.69 ±0.21 / 11.99 ms │        11.43 / 11.62 ±0.19 / 11.99 ms │     no change │
│ QQuery 69 │        54.78 / 56.81 ±3.10 / 62.90 ms │        55.11 / 56.30 ±1.49 / 59.23 ms │     no change │
│ QQuery 70 │     101.76 / 102.69 ±0.64 / 103.71 ms │     102.78 / 105.84 ±2.10 / 108.45 ms │     no change │
│ QQuery 71 │        34.55 / 34.86 ±0.21 / 35.17 ms │        34.66 / 34.84 ±0.10 / 34.95 ms │     no change │
│ QQuery 72 │ 1625.26 / 1674.03 ±57.55 / 1783.94 ms │ 1509.84 / 1599.73 ±82.07 / 1728.58 ms │     no change │
│ QQuery 73 │        10.09 / 10.63 ±0.42 / 11.22 ms │          9.54 / 9.84 ±0.33 / 10.34 ms │ +1.08x faster │
│ QQuery 74 │     188.51 / 191.18 ±3.63 / 198.25 ms │     186.74 / 191.35 ±5.00 / 200.18 ms │     no change │
│ QQuery 75 │     135.87 / 137.63 ±1.53 / 140.33 ms │     136.87 / 138.60 ±1.78 / 140.86 ms │     no change │
│ QQuery 76 │        34.00 / 34.19 ±0.12 / 34.38 ms │        34.03 / 34.29 ±0.18 / 34.54 ms │     no change │
│ QQuery 77 │        58.74 / 59.48 ±1.01 / 61.44 ms │        58.90 / 59.39 ±0.60 / 60.57 ms │     no change │
│ QQuery 78 │     269.46 / 276.43 ±7.38 / 289.91 ms │    262.12 / 280.39 ±15.07 / 303.11 ms │     no change │
│ QQuery 79 │        66.63 / 68.65 ±3.29 / 75.21 ms │        65.76 / 66.68 ±0.82 / 68.18 ms │     no change │
│ QQuery 80 │        93.73 / 95.58 ±2.05 / 99.43 ms │       93.31 / 97.14 ±3.40 / 102.43 ms │     no change │
│ QQuery 81 │        25.86 / 26.46 ±0.94 / 28.32 ms │        25.17 / 25.44 ±0.18 / 25.67 ms │     no change │
│ QQuery 82 │        16.70 / 17.55 ±1.45 / 20.45 ms │        15.97 / 16.51 ±0.94 / 18.39 ms │ +1.06x faster │
│ QQuery 83 │        32.99 / 33.44 ±0.27 / 33.82 ms │        31.54 / 32.47 ±0.92 / 34.08 ms │     no change │
│ QQuery 84 │        30.02 / 31.94 ±3.24 / 38.39 ms │        28.88 / 29.26 ±0.34 / 29.83 ms │ +1.09x faster │
│ QQuery 85 │       97.78 / 99.14 ±1.32 / 101.52 ms │       97.79 / 99.63 ±2.16 / 103.80 ms │     no change │
│ QQuery 86 │        25.83 / 26.36 ±0.75 / 27.84 ms │        24.77 / 24.97 ±0.14 / 25.19 ms │ +1.06x faster │
│ QQuery 87 │        62.07 / 62.66 ±0.50 / 63.54 ms │        59.38 / 60.22 ±0.84 / 61.83 ms │     no change │
│ QQuery 88 │        59.64 / 60.68 ±1.52 / 63.67 ms │        58.38 / 58.80 ±0.31 / 59.20 ms │     no change │
│ QQuery 89 │        35.77 / 35.96 ±0.19 / 36.31 ms │        35.08 / 35.43 ±0.24 / 35.80 ms │     no change │
│ QQuery 90 │        16.56 / 16.76 ±0.12 / 16.91 ms │        15.72 / 15.89 ±0.15 / 16.13 ms │ +1.05x faster │
│ QQuery 91 │        40.27 / 41.32 ±0.97 / 43.06 ms │        39.65 / 39.74 ±0.09 / 39.90 ms │     no change │
│ QQuery 92 │        30.24 / 30.58 ±0.26 / 31.04 ms │        28.67 / 29.36 ±0.65 / 30.57 ms │     no change │
│ QQuery 93 │        50.07 / 51.74 ±2.76 / 57.24 ms │        48.50 / 49.15 ±0.50 / 49.78 ms │ +1.05x faster │
│ QQuery 94 │        38.66 / 39.70 ±0.70 / 40.55 ms │        37.56 / 39.31 ±1.57 / 42.18 ms │     no change │
│ QQuery 95 │        81.07 / 82.31 ±1.32 / 84.84 ms │        78.58 / 79.34 ±0.49 / 80.03 ms │     no change │
│ QQuery 96 │        24.12 / 24.26 ±0.09 / 24.38 ms │        23.35 / 23.70 ±0.26 / 24.14 ms │     no change │
│ QQuery 97 │        51.79 / 54.31 ±3.90 / 61.99 ms │        49.56 / 50.45 ±0.82 / 51.82 ms │ +1.08x faster │
│ QQuery 98 │        43.51 / 43.88 ±0.32 / 44.44 ms │        42.17 / 42.88 ±0.81 / 44.46 ms │     no change │
│ QQuery 99 │        64.91 / 65.73 ±0.95 / 67.47 ms │        64.83 / 65.08 ±0.21 / 65.38 ms │     no change │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                      ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                      │ 9240.73ms │
│ Total Time (routed-lookup-array-map)   │ 9181.48ms │
│ Average Time (HEAD)                    │   93.34ms │
│ Average Time (routed-lookup-array-map) │   92.74ms │
│ Queries Faster                         │         8 │
│ Queries Slower                         │         1 │
│ Queries with No Change                 │        90 │
│ Queries with Failure                   │         0 │
└────────────────────────────────────────┴───────────┘

Resource Usage

tpcds — base (merge-base)

Metric Value
Wall time 50.0s
Peak memory 2.1 GiB
Avg memory 1.4 GiB
CPU user 188.3s
CPU sys 5.6s
Peak spill 0 B

tpcds — branch

Metric Value
Wall time 50.0s
Peak memory 2.3 GiB
Avg memory 1.6 GiB
CPU user 183.8s
CPU sys 5.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing routed-lookup-array-map (97db09b) to 70f2ed0 (merge-base) diff

Run configuration
run benchmark tpch10
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and routed-lookup-array-map
--------------------
Benchmark tpch_sf10.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃      HEAD ┃ routed-lookup-array-map ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 1  │ 338.84 ms │               337.01 ms │ no change │
│ QQuery 2  │  92.32 ms │                91.03 ms │ no change │
│ QQuery 3  │ 231.46 ms │               228.83 ms │ no change │
│ QQuery 4  │ 120.25 ms │               119.42 ms │ no change │
│ QQuery 5  │ 364.50 ms │               369.34 ms │ no change │
│ QQuery 6  │ 103.89 ms │               103.43 ms │ no change │
│ QQuery 7  │ 467.35 ms │               475.54 ms │ no change │
│ QQuery 8  │ 371.83 ms │               365.62 ms │ no change │
│ QQuery 9  │ 540.44 ms │               538.14 ms │ no change │
│ QQuery 10 │ 302.34 ms │               304.40 ms │ no change │
│ QQuery 11 │  65.31 ms │                66.78 ms │ no change │
│ QQuery 12 │ 124.55 ms │               123.19 ms │ no change │
│ QQuery 13 │ 320.72 ms │               324.37 ms │ no change │
│ QQuery 14 │ 175.76 ms │               178.69 ms │ no change │
│ QQuery 15 │ 314.49 ms │               311.17 ms │ no change │
│ QQuery 16 │  67.22 ms │                67.11 ms │ no change │
│ QQuery 17 │ 636.80 ms │               639.38 ms │ no change │
│ QQuery 18 │ 997.16 ms │              1006.21 ms │ no change │
│ QQuery 19 │ 239.93 ms │               240.83 ms │ no change │
│ QQuery 20 │ 279.32 ms │               272.42 ms │ no change │
│ QQuery 21 │ 701.78 ms │               691.54 ms │ no change │
│ QQuery 22 │  62.81 ms │                63.87 ms │ no change │
└───────────┴───────────┴─────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                      ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                      │ 6919.08ms │
│ Total Time (routed-lookup-array-map)   │ 6918.33ms │
│ Average Time (HEAD)                    │  314.50ms │
│ Average Time (routed-lookup-array-map) │  314.47ms │
│ Queries Faster                         │         0 │
│ Queries Slower                         │         0 │
│ Queries with No Change                 │        22 │
│ Queries with Failure                   │         0 │
└────────────────────────────────────────┴───────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and routed-lookup-array-map
--------------------
Benchmark tpch_sf10.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                 HEAD ┃               routed-lookup-array-map ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │    338.84 / 341.79 ±2.31 / 345.13 ms │     337.01 / 338.85 ±1.02 / 339.89 ms │     no change │
│ QQuery 2  │       92.32 / 96.53 ±2.27 / 99.17 ms │        91.03 / 94.59 ±2.27 / 98.11 ms │     no change │
│ QQuery 3  │    231.46 / 235.73 ±2.99 / 240.82 ms │     228.83 / 232.80 ±2.72 / 236.48 ms │     no change │
│ QQuery 4  │    120.25 / 122.17 ±1.33 / 123.92 ms │     119.42 / 121.59 ±2.37 / 126.08 ms │     no change │
│ QQuery 5  │    364.50 / 377.71 ±6.83 / 383.67 ms │    369.34 / 382.84 ±20.00 / 421.78 ms │     no change │
│ QQuery 6  │    103.89 / 106.79 ±2.08 / 110.01 ms │     103.43 / 106.06 ±2.39 / 109.98 ms │     no change │
│ QQuery 7  │   467.35 / 483.12 ±10.26 / 493.15 ms │     475.54 / 487.14 ±8.61 / 496.32 ms │     no change │
│ QQuery 8  │    371.83 / 375.23 ±2.89 / 378.90 ms │     365.62 / 373.32 ±5.59 / 382.89 ms │     no change │
│ QQuery 9  │   540.44 / 574.38 ±49.08 / 671.93 ms │    538.14 / 555.39 ±14.90 / 579.33 ms │     no change │
│ QQuery 10 │    302.34 / 307.92 ±5.88 / 318.01 ms │     304.40 / 308.49 ±2.68 / 311.72 ms │     no change │
│ QQuery 11 │       65.31 / 66.40 ±0.58 / 66.98 ms │        66.78 / 68.04 ±1.13 / 69.83 ms │     no change │
│ QQuery 12 │    124.55 / 134.17 ±9.08 / 147.70 ms │     123.19 / 126.02 ±2.17 / 128.81 ms │ +1.06x faster │
│ QQuery 13 │    320.72 / 327.19 ±7.43 / 338.14 ms │     324.37 / 328.94 ±3.04 / 332.19 ms │     no change │
│ QQuery 14 │    175.76 / 181.80 ±4.69 / 188.44 ms │     178.69 / 182.60 ±3.80 / 188.36 ms │     no change │
│ QQuery 15 │    314.49 / 320.28 ±6.16 / 331.96 ms │     311.17 / 315.09 ±2.15 / 317.26 ms │     no change │
│ QQuery 16 │       67.22 / 72.93 ±7.49 / 87.31 ms │        67.11 / 68.94 ±1.82 / 72.13 ms │ +1.06x faster │
│ QQuery 17 │    636.80 / 650.28 ±9.41 / 662.85 ms │     639.38 / 648.51 ±5.26 / 655.06 ms │     no change │
│ QQuery 18 │ 997.16 / 1025.45 ±28.53 / 1079.49 ms │ 1006.21 / 1017.18 ±11.45 / 1036.37 ms │     no change │
│ QQuery 19 │   239.93 / 257.74 ±20.41 / 295.24 ms │    240.83 / 261.07 ±19.31 / 286.15 ms │     no change │
│ QQuery 20 │    279.32 / 289.49 ±5.34 / 294.47 ms │    272.42 / 286.48 ±11.15 / 304.57 ms │     no change │
│ QQuery 21 │    701.78 / 711.51 ±7.12 / 721.41 ms │    691.54 / 708.88 ±10.81 / 721.18 ms │     no change │
│ QQuery 22 │       62.81 / 66.18 ±2.73 / 69.42 ms │        63.87 / 67.52 ±4.88 / 77.18 ms │     no change │
└───────────┴──────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                      ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                      │ 7124.82ms │
│ Total Time (routed-lookup-array-map)   │ 7080.35ms │
│ Average Time (HEAD)                    │  323.86ms │
│ Average Time (routed-lookup-array-map) │  321.83ms │
│ Queries Faster                         │         2 │
│ Queries Slower                         │         0 │
│ Queries with No Change                 │        20 │
│ Queries with Failure                   │         0 │
└────────────────────────────────────────┴───────────┘

Resource Usage

tpch10 — base (merge-base)

Metric Value
Wall time 40.0s
Peak memory 13.5 GiB
Avg memory 2.6 GiB
CPU user 360.8s
CPU sys 22.5s
Peak spill 0 B

tpch10 — branch

Metric Value
Wall time 40.0s
Peak memory 13.6 GiB
Avg memory 2.7 GiB
CPU user 359.6s
CPU sys 22.6s
Peak spill 0 B

File an issue against this benchmark runner

…ed-lookup-array-map

# Conflicts:
#	datafusion/physical-plan/src/joins/hash_join/partitioned_hash_eval.rs
#	datafusion/physical-plan/src/joins/hash_join/shared_bounds.rs

@jayzhan211 jayzhan211 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adriangb thanks for this. In shared_bounds.rs around line 994, please drop the all-Range early return in merged_pruning_bitmap. Dense partitions usually have no bitmap, so this now returns None for them, and Range-partitioned joins stop pruning the gaps between partitions: base prunes 4 of 4 probe files, this PR prunes 1 of 4, and removing the return prunes 4 of 4. union already returns None when every bucket is set.

-    /// bounds. `None` when no partition narrows its bounds, as the bounds
-    /// predicate already prunes that much.
+    /// bounds. `None` when nothing can be excluded.
-        if parts
-            .iter()
-            .all(|part| matches!(part, KeyRangePart::Range { .. }))
-        {
-            return None;
-        }
         KeyRangeBitmap::union(&merged.min, &merged.max, &parts).map(Arc::new)
Repro setup and a regression test (the test needs `array_map_of` from my comment on the merge gate)

Repro: Partitioned join, Range splits (10, 20, 30), hash_join_inlist_pushdown_max_distinct_values = 0. Build keys {7,8,9} {17,18,19} {27,28,29} {37,38,39}, probe range_partitioned. Bytes scanned: base 0 B, this PR 126 B, with the fix 0 B.

#[test]
fn disjoint_array_map_partitions_keep_gap_pruning() {
    let acc = make_partitioned_expr_accumulator_for_test(2);
    let members = [
        (0, array_map_of(&[7, 8, 9]), bounds(7, 9)),
        (1, array_map_of(&[37, 38, 39]), bounds(37, 39)),
    ];

    let bitmap = acc
        .merged_pruning_bitmap(&members, Some(&bounds(7, 39)))
        .expect("the gap between the partitions can be pruned");

    assert!(bitmap.may_contain_range(7, 9));
    assert!(!bitmap.may_contain_range(10, 36));
}

Optional cleanup: a few comments still describe hash tables only, now that partitions can be array maps. They are the Lookup::Routed doc (partitioned_hash_eval.rs line 284), the evaluate_routed doc (line 421), and the merged_membership_filter doc (shared_bounds.rs line 860).

// An array map is keyed by value, not hash, so it probes
// the run's own key values.
Map::ArrayMap(map) => {
let indices = UInt32Array::from(rows[run.clone()].to_vec());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When every partition is an array map, with_hashes and sorted_hashes do per-row work that nothing reads. Skipping them took lookup cost from 4.8 to 4.1 ns/row at 16 partitions and batch 8192, measured with a local variant on a busy laptop. It's fine to handle this in a follow-up, since it only saves time and needs the closure reshaped. The condition to hash:

let needs_hashes = maps.iter().flatten().any(|map| {
    let map: &Map = map;
    matches!(map, Map::HashMap(_))
});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left for a follow-up, as you suggested: this PR keeps hashing every row.

🤖 Addressed by Claude Code

Array map partitions now join the merged lookup, and a dense partition
usually has no pruning bitmap, so it contributes its whole bounds. The
merged pruning bitmap returned `None` when every partition contributed
only bounds, so a Range-partitioned join stopped pruning the probe
containers that fall in the gaps between partitions. `union` already
returns `None` when no bucket can be excluded, so the early return goes.

This also adds tests that array map partitions reach the merged filter
under hash and range routing. The fuzz test keeps hash tables under
`force_hash_collisions`, where a hash table matches every key and an
array map would disagree with the reference. The remaining changes are
doc wording for array maps, `take_arrays`, and a simpler test helper.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@adriangb

adriangb commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

@jayzhan211 could you take another look here? Thanks!

@jayzhan211 jayzhan211 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @adriangb!

@jayzhan211
jayzhan211 added this pull request to the merge queue Nov 11, 2026
@adriangb

Copy link
Copy Markdown
Contributor Author

Thanks @adriangb!

Thank you for helping review!

Merged via the queue into apache:main with commit ced13f8 Nov 11, 2026
44 checks passed
geoffreyclaude pushed a commit to geoffreyclaude/datafusion that referenced this pull request Nov 12, 2026
…ray map (apache#27324)

## Which issue does this PR close?

- Follow-up to apache#27091, from
review feedback there.

## Rationale for this change

A `Partitioned` hash join with dense integer keys builds an `ArrayMap`
in every partition. Its dynamic filter then computes a hash for every
probe row, but an `ArrayMap` looks keys up by value, so nothing reads
those hashes. Skipping them makes the filter cheaper on every probe
batch.

## What changes are included in this PR?

`HashTableLookupExpr::evaluate_routed` hashes the probe keys only when
at least one partition is a hash table. The counting sort by partition
runs either way.

## What is the testing strategy for this PR?

- A new unit test builds every partition as an `ArrayMap` and checks
exact matches, including a null probe row.
- The routed lookup fuzz test passes with and without
`force_hash_collisions`.
- Lookup cost on a GCP VM (16 partitions, batch 8192): 7.49 → 6.56
ns/row.

## Are there any user-facing changes?

No.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
andygrove pushed a commit to andygrove/datafusion that referenced this pull request Nov 12, 2026
…he#27092)

## Which issue does this PR close?

- This PR does not close an issue. It follows up on
apache#21666, which added canceled
partitions to the hash join dynamic filter to fix
apache#21625.

## Rationale for this change

A `Partitioned` hash join cancels one of its partitions when a parent
operator drops that partition's stream before it reports its build side.
For example, a parent join partition whose own build side is empty drops
its probe-side stream unpolled. The dynamic filter keeps every probe row
routed to a canceled partition, because that partition's build keys are
unknown.

Keeping those rows buys nothing. A stream starts to probe only after its
report is delivered, so a canceled stream has emitted no row and never
will. The shared probe input still reads the rows routed to it, and
`RepartitionExec` then discards them. Keeping them also costs something:

- A canceled partition forces the routed `CASE` fallback instead of the
merged lookup. After apache#27091 it
is the only thing that does.
- Under `NullEqualsNull`, a canceled partition makes every live
partition keep probe-side NULL rows.

## What changes are included in this PR?

Three commits:

1. `test:` Two dynamic filter tests checked range routing for `-0.0` and
for composite nullable keys through a canceled partition's `CASE`
branch. The commit moves both cases into `RangeRouter` tests, before the
next commit removes that branch.
2. `fix:` A canceled partition counts as empty, so the filter rejects
the rows routed to it. The commit rewrites the tests that asserted the
old behavior.
3. `refactor:` The `CASE` fallback has no input left. The commit removes
it, the per-partition filters it used, and the test assertions that a
filter is not a `CASE`. When exactly one partition holds rows, the
filter is still that partition's own IN list or hash lookup, so the
probe scan keeps bloom filter pruning.
4. `fix:` Restores the branch for a lone non-empty partition, which the
refactor first dropped. Adds a test for it and for a canceled partition
next to live ones, and removes the remaining `CASE` wording.

This is +155 / −345 lines.

## What is the testing strategy for this PR?

- The new `RangeRouter` tests keep the routing cases that the removed
tests covered.
- `partitioned_canceled_and_empty_partitions_reject_every_row` and
`partitioned_canceled_partition_does_not_widen_filter` cover the new
behavior.
- `test_partitioned_dynamic_filter_reports_empty_canceled_partitions`,
the regression test for
apache#21625, still passes.
- All `datafusion-physical-plan` tests, all sqllogictests, and
`core_integration` pass.

I also checked the behavior on a query that cancels partitions. In
`SELECT x.k FROM (SELECT big.k FROM mid JOIN big ON mid.k = big.k) x
WHERE x.k IN (SELECT k FROM tiny)` with 4 partitions, the parent
`RightSemi` join cancels two child partitions. The result is the same
with and without this PR.

## Are there any user-facing changes?

No.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

physical-plan Changes to the physical-plan crate v57.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants