Skip to content

Add filter pushdown scatter threshold#9414

Open
Dandandan wants to merge 17 commits intoapache:mainfrom
Dandandan:selectivity_threshold
Open

Add filter pushdown scatter threshold#9414
Dandandan wants to merge 17 commits intoapache:mainfrom
Dandandan:selectivity_threshold

Conversation

@Dandandan
Copy link
Copy Markdown
Contributor

@Dandandan Dandandan commented Feb 14, 2026

Which issue does this PR close?

Rationale for this change

It can be better to altogether skip (combined) filters with low effectivity - as there still will be overhead of individual (small) skip/read during Parquet decoder.

What changes are included in this PR?

This adds a simple threshold to skip pushing down if the current selection is not "effective", i.e. under a fraction of rows

Are these changes tested?

Are there any user-facing changes?

Dandandan and others added 4 commits February 14, 2026 17:05
Previously, every predicate in the RowFilter received the same
ProjectionMask containing ALL filter columns. This caused unnecessary
decoding of expensive string columns when evaluating cheap integer
predicates. Now each predicate receives a mask with only the single
column it needs.

Key sync improvements (vs baseline):
- Q37: 63.7ms -> 7.3ms  (-88.6%, Title LIKE with CounterID=62 filter)
- Q36: 117ms -> 24ms    (-79.5%, URL <> '' with CounterID=62 filter)
- Q40: 17.9ms -> 5.1ms  (-71.5%, multi-pred with RefererHash eq)
- Q41: 17.3ms -> 5.5ms  (-68.1%, multi-pred with URLHash eq)
- Q22: 303ms -> 127ms   (-58.2%, 3 string predicates)
- Q42: 7.6ms -> 3.9ms   (-48.5%, int-only multi-predicate)
- Q38: 19.1ms -> 12.4ms (-34.9%, 5 int predicates)
- Q21: 159ms -> 98ms     (-38.5%, URL LIKE + SearchPhrase)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use page-level min/max statistics (via StatisticsConverter) to compute
a RowSelection that skips pages where equality predicates cannot match.
For each equality predicate with an integer literal, we check if the
literal falls within each page's [min, max] range and skip pages where
it doesn't.

Impact is data-dependent - most effective when data is sorted/clustered
by the filter column. For this particular 100K-row sample file the data
isn't sorted by filter columns, so improvements are modest (~5% for
some CounterID=62 queries). Would show larger gains on sorted datasets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Put the cheapest/most selective predicate first: SearchPhrase <> ''
filters ~87% of rows before expensive LIKE predicates run. This
reduces string column decoding for Title and URL significantly.

Q22 sync: ~6% improvement, Q22 async: ~13% improvement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the parquet Changes to the parquet crate label Feb 14, 2026
@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@Dandandan Dandandan changed the title [PoC] Selectivity threshold [PoC] Filter pushdown selectivity threshold Feb 14, 2026
@alamb-ghbot
Copy link
Copy Markdown

🤖 ./gh_compare_arrow.sh gh_compare_arrow.sh Running
Linux aal-dev 6.14.0-1018-gcp #19~24.04.1-Ubuntu SMP Wed Sep 24 23:23:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Comparing selectivity_threshold (b4275cb) to 39a2b71 diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
BENCH_BRANCH_NAME=selectivity_threshold
Results will be posted here when complete

@alamb-ghbot
Copy link
Copy Markdown

🤖: Benchmark completed

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00      2.3±0.03ms        ? ?/sec    1.00      2.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.01     11.6±0.40ms        ? ?/sec    1.00     11.5±0.40ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.00     13.0±0.27ms        ? ?/sec    1.03     13.4±0.46ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.00     23.1±0.38ms        ? ?/sec    1.01     23.5±0.35ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.00     28.5±0.28ms        ? ?/sec    1.01     28.9±0.41ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.00     25.5±0.19ms        ? ?/sec    1.02     26.0±0.45ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      5.6±0.10ms        ? ?/sec    1.04      5.8±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.12   128.4±11.83ms        ? ?/sec    1.00    114.8±0.57ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.30    166.3±1.04ms        ? ?/sec    1.00    128.1±1.42ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.31    241.9±1.35ms        ? ?/sec    1.00    185.3±4.95ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.00    412.2±2.41ms        ? ?/sec    1.00    412.5±5.81ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.00     32.1±0.70ms        ? ?/sec    1.00     32.1±0.31ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.00    100.9±0.68ms        ? ?/sec    1.00    100.6±0.66ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.00     98.7±1.00ms        ? ?/sec    1.00     98.3±0.63ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.00     28.1±0.32ms        ? ?/sec    1.00     28.1±0.28ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 4.26    118.8±0.61ms        ? ?/sec    1.00     27.9±0.51ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 12.22    93.9±0.68ms        ? ?/sec    1.00      7.7±0.13ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.40     35.7±0.81ms        ? ?/sec    1.00     25.5±0.24ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.04     46.2±0.32ms        ? ?/sec    1.00     44.5±0.47ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 3.95     40.7±0.51ms        ? ?/sec    1.00     10.3±0.25ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 3.48     29.8±0.44ms        ? ?/sec    1.00      8.6±0.24ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.97     11.0±0.07ms        ? ?/sec    1.00      5.6±0.10ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00      2.2±0.04ms        ? ?/sec    1.01      2.3±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00     11.2±0.30ms        ? ?/sec    1.00     11.2±0.31ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.01     12.7±0.37ms        ? ?/sec    1.00     12.6±0.41ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.00     22.5±0.20ms        ? ?/sec    1.00     22.6±0.30ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.00     27.6±0.31ms        ? ?/sec    1.00     27.7±0.28ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.00     25.0±0.27ms        ? ?/sec    1.00     25.1±0.25ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      5.2±0.09ms        ? ?/sec    1.01      5.2±0.11ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.00    110.9±1.31ms        ? ?/sec    1.00    110.7±1.00ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.03    126.8±0.89ms        ? ?/sec    1.00    123.3±1.12ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.52    233.5±1.32ms        ? ?/sec    1.00    153.2±0.99ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.04   361.3±24.92ms        ? ?/sec    1.00    347.2±1.65ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.00     30.2±0.29ms        ? ?/sec    1.02     30.8±0.50ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.00     96.1±0.81ms        ? ?/sec    1.00     95.8±0.62ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.00     94.2±1.01ms        ? ?/sec    1.00     94.3±0.64ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.00     26.9±0.25ms        ? ?/sec    1.01     27.1±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    4.53    113.6±0.58ms        ? ?/sec    1.00     25.1±0.26ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    12.06    90.0±0.61ms        ? ?/sec    1.00      7.5±0.10ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.43     32.6±0.67ms        ? ?/sec    1.00     22.8±0.28ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.05     41.5±0.31ms        ? ?/sec    1.00     39.7±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    4.07     39.0±0.68ms        ? ?/sec    1.00      9.6±0.17ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    3.55     28.2±0.30ms        ? ?/sec    1.00      7.9±0.15ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.98     10.5±0.12ms        ? ?/sec    1.00      5.3±0.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.00  1983.5±13.50µs        ? ?/sec    1.01  1993.7±15.84µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.00      7.5±0.08ms        ? ?/sec    1.00      7.6±0.10ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      9.0±0.07ms        ? ?/sec    1.00      9.0±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.00     29.6±1.36ms        ? ?/sec    1.02     30.1±1.19ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     34.3±0.67ms        ? ?/sec    1.20     41.3±1.39ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.23     39.1±1.01ms        ? ?/sec    1.00     31.8±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.00      4.2±0.04ms        ? ?/sec    1.01      4.2±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.01    179.3±1.24ms        ? ?/sec    1.00    177.6±2.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.73    231.3±5.30ms        ? ?/sec    1.00    133.8±1.14ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  2.30    481.2±3.88ms        ? ?/sec    1.00    208.9±1.42ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.06   448.8±16.62ms        ? ?/sec    1.00    422.6±6.25ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.02     39.9±0.35ms        ? ?/sec    1.00     39.0±0.33ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.00    154.8±1.28ms        ? ?/sec    1.01    156.1±1.15ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.00    149.5±1.60ms        ? ?/sec    1.01    150.4±0.98ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.00     28.3±0.40ms        ? ?/sec    1.00     28.4±0.30ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  4.77    153.9±1.60ms        ? ?/sec    1.00     32.2±0.49ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  9.86     85.9±0.63ms        ? ?/sec    1.00      8.7±0.07ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.53     28.4±0.46ms        ? ?/sec    1.00     18.5±0.24ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.06     34.0±0.45ms        ? ?/sec    1.00     32.0±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  3.06     26.6±0.58ms        ? ?/sec    1.00      8.7±0.28ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  3.92     27.9±0.30ms        ? ?/sec    1.00      7.1±0.09ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.76     11.8±0.10ms        ? ?/sec    1.00      6.7±0.23ms        ? ?/sec

@Dandandan
Copy link
Copy Markdown
Contributor Author

Dandandan commented Feb 14, 2026

Nice this shows some good resulrs @alamb @adriangb (need to merge #9413) so we can run the benchmark again and compare (current crazy difference is due to projection issue addressed in other PR).

@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@Dandandan Dandandan marked this pull request as ready for review February 16, 2026 09:01
@Dandandan Dandandan changed the title [PoC] Filter pushdown selectivity threshold Filter pushdown selectivity threshold Feb 16, 2026
@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@Dandandan
Copy link
Copy Markdown
Contributor Author

@alamb can you get the runner "unstuck" again? :D

@alamb
Copy link
Copy Markdown
Contributor

alamb commented Feb 17, 2026

@alamb can you get the runner "unstuck" again? :D

Done

What I think is happening is that the runer is being oomkilled:

[9206835.020555] Out of memory: Killed process 2715082 (dfbench) total-vm:47838332kB, anon-rss:31959228kB, file-rss:2792kB, shmem-rss:0kB, UID:1001 pgtables:63624kB oom_score_adj:0

@adriangb
Copy link
Copy Markdown
Contributor

I won't schedule any more benchmarks from that branch. Interesting about the mem usage.

@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@alamb-ghbot
Copy link
Copy Markdown

🤖 ./gh_compare_arrow.sh gh_compare_arrow.sh Running
Linux aal-dev 6.14.0-1018-gcp #19~24.04.1-Ubuntu SMP Wed Sep 24 23:23:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Comparing selectivity_threshold (06954d5) to df63590 diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
BENCH_BRANCH_NAME=selectivity_threshold
Results will be posted here when complete

@alamb-ghbot
Copy link
Copy Markdown

🤖: Benchmark completed

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00      2.3±0.03ms        ? ?/sec    1.01      2.3±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00     10.4±0.18ms        ? ?/sec    1.02     10.6±0.18ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.01     12.2±0.45ms        ? ?/sec    1.00     12.1±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.00     21.5±0.14ms        ? ?/sec    1.04     22.4±0.43ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.00     26.8±0.47ms        ? ?/sec    1.03     27.5±0.45ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.00     23.8±0.44ms        ? ?/sec    1.04     24.7±0.29ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      5.3±0.16ms        ? ?/sec    1.00      5.3±0.10ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.00    111.7±0.99ms        ? ?/sec    1.02    113.5±1.08ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.00    124.3±0.55ms        ? ?/sec    1.01    125.8±0.64ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.00    180.4±7.16ms        ? ?/sec    1.05    189.6±5.89ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.00    399.7±2.20ms        ? ?/sec    1.02    405.8±4.17ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.00     29.7±0.22ms        ? ?/sec    1.03     30.4±0.18ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.00     97.5±0.66ms        ? ?/sec    1.01     98.5±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.00     95.3±0.92ms        ? ?/sec    1.01     96.6±0.88ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.00     26.2±0.60ms        ? ?/sec    1.04     27.1±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.08     28.6±0.35ms        ? ?/sec    1.00     26.6±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.28      9.5±0.11ms        ? ?/sec    1.00      7.4±0.17ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.00     24.7±0.55ms        ? ?/sec    1.00     24.7±0.25ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.00     42.3±0.28ms        ? ?/sec    1.02     43.2±0.46ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.37     13.2±0.17ms        ? ?/sec    1.00      9.7±0.13ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.31     10.3±0.14ms        ? ?/sec    1.00      7.9±0.11ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.06      5.8±0.05ms        ? ?/sec    1.00      5.4±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00      2.3±0.05ms        ? ?/sec    1.00      2.3±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00     10.0±0.15ms        ? ?/sec    1.01     10.1±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00     11.5±0.12ms        ? ?/sec    1.09     12.5±1.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.00     21.0±0.12ms        ? ?/sec    1.03     21.7±0.30ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.00     25.6±0.19ms        ? ?/sec    1.05     26.8±0.40ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.00     23.4±0.20ms        ? ?/sec    1.05     24.5±0.46ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      4.9±0.02ms        ? ?/sec    1.04      5.1±0.11ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.00    107.4±0.40ms        ? ?/sec    1.02    110.0±0.62ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.00    119.9±1.47ms        ? ?/sec    1.03    123.3±0.75ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.00    147.7±1.00ms        ? ?/sec    1.05    155.5±4.89ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.02    365.0±3.70ms        ? ?/sec    1.00   356.3±13.16ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.04     30.5±0.83ms        ? ?/sec    1.00     29.4±0.41ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.00     95.1±1.25ms        ? ?/sec    1.00     94.9±0.54ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.00     92.7±1.24ms        ? ?/sec    1.00     92.9±1.48ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.00     26.9±0.31ms        ? ?/sec    1.00     26.8±0.35ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.11     27.5±0.52ms        ? ?/sec    1.00     24.7±0.39ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.32      9.5±0.11ms        ? ?/sec    1.00      7.2±0.07ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.04     23.0±0.28ms        ? ?/sec    1.00     22.1±0.33ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     38.9±0.64ms        ? ?/sec    1.02     39.7±0.92ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.38     13.3±0.26ms        ? ?/sec    1.00      9.6±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.32     10.1±0.24ms        ? ?/sec    1.00      7.7±0.21ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.08      5.6±0.09ms        ? ?/sec    1.00      5.2±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.00  1994.7±19.04µs        ? ?/sec    1.00   1993.9±8.82µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.01      7.6±0.12ms        ? ?/sec    1.00      7.5±0.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      8.8±0.09ms        ? ?/sec    1.00      8.8±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.00     29.1±1.34ms        ? ?/sec    1.00     29.2±1.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     33.2±0.73ms        ? ?/sec    1.20     39.8±1.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     30.1±0.26ms        ? ?/sec    1.03     30.9±0.14ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.01      4.2±0.02ms        ? ?/sec    1.00      4.1±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.00    172.2±1.42ms        ? ?/sec    1.02    176.1±1.60ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.00    128.6±0.80ms        ? ?/sec    1.02    131.1±1.22ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.00    205.2±1.96ms        ? ?/sec    1.01    206.6±1.81ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.00    418.9±4.91ms        ? ?/sec    1.02    425.5±9.73ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.00     38.9±1.12ms        ? ?/sec    1.02     39.9±0.45ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.00    148.7±0.86ms        ? ?/sec    1.03    152.7±1.50ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.00    143.1±1.25ms        ? ?/sec    1.02    146.6±1.71ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.00     27.0±0.39ms        ? ?/sec    1.01     27.3±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.07     32.6±0.77ms        ? ?/sec    1.00     30.6±0.23ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.22     10.4±0.06ms        ? ?/sec    1.00      8.5±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.00     17.8±0.26ms        ? ?/sec    1.00     17.8±0.16ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.00     30.1±0.26ms        ? ?/sec    1.02     30.8±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.10      9.0±0.08ms        ? ?/sec    1.00      8.2±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.33      9.1±0.05ms        ? ?/sec    1.00      6.9±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.04      6.7±0.04ms        ? ?/sec    1.00      6.4±0.13ms        ? ?/sec

@Dandandan
Copy link
Copy Markdown
Contributor Author

Dandandan commented Feb 17, 2026

Nice

arrow_reader_clickbench/async/Q36                 1.08     28.6±0.35ms        ? ?/sec    1.00     26.6±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.28      9.5±0.11ms        ? ?/sec    1.00      7.4±0.17ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.37     13.2±0.17ms        ? ?/sec    1.00      9.7±0.13ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.31     10.3±0.14ms        ? ?/sec    1.00      7.9±0.11ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.06      5.8±0.05ms        ? ?/sec    1.00      5.4±0.04ms        ? ?/sec```

@Dandandan Dandandan marked this pull request as draft March 19, 2026 18:50
@Dandandan
Copy link
Copy Markdown
Contributor Author

Actually I think we should just have / try this.

@Dandandan Dandandan marked this pull request as ready for review March 19, 2026 20:21
@Dandandan
Copy link
Copy Markdown
Contributor Author

Looking at the code here I think this may make sense regardless of the work on the DataFusion side. It's a relatively small self contained change. Even if we move filters from row filters to non row filters (which has implications for IO, etc.) this at the very least saves compute applying pointless fragmented masks (if I understand the change correctly), right?

Yes, I think it's pretty effective, simple, and does something DataFusion can not handle yet (skip applying the mask indeed).

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Linux bench-c4095543573-474-jlx7m 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing selectivity_threshold (155a1fc) to d53df60 (merge-base) diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
Results will be posted here when complete

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00  1092.8±13.79µs        ? ?/sec    1.00   1090.9±4.96µs        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00      6.8±0.18ms        ? ?/sec    1.01      6.9±0.08ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.00      7.8±0.03ms        ? ?/sec    1.00      7.7±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.00     14.8±0.25ms        ? ?/sec    1.00     14.9±0.21ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.01     17.6±0.24ms        ? ?/sec    1.00     17.5±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.01     16.3±0.28ms        ? ?/sec    1.00     16.1±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.01      3.1±0.05ms        ? ?/sec    1.00      3.1±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.09     78.1±4.42ms        ? ?/sec    1.00     71.9±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.21     96.9±0.94ms        ? ?/sec    1.00     80.2±0.26ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.17    131.5±5.71ms        ? ?/sec    1.00    112.9±0.57ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.03    247.5±1.51ms        ? ?/sec    1.00    239.4±1.46ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.02     19.9±0.25ms        ? ?/sec    1.00     19.5±0.18ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.02     58.4±0.59ms        ? ?/sec    1.00     57.3±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.01     58.2±0.58ms        ? ?/sec    1.00     57.5±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.01     18.9±0.16ms        ? ?/sec    1.00     18.8±0.19ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.07     16.0±0.45ms        ? ?/sec    1.00     14.9±0.40ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.03      5.5±0.03ms        ? ?/sec    1.00      5.3±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.08     14.2±0.41ms        ? ?/sec    1.00     13.2±0.18ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.04     25.1±0.60ms        ? ?/sec    1.00     24.1±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.04      5.9±0.14ms        ? ?/sec    1.00      5.7±0.09ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.04      5.1±0.07ms        ? ?/sec    1.00      4.9±0.07ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.02      3.6±0.03ms        ? ?/sec    1.00      3.5±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.01   1073.2±7.90µs        ? ?/sec    1.00   1066.5±1.99µs        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00      6.6±0.09ms        ? ?/sec    1.00      6.6±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00      7.6±0.20ms        ? ?/sec    1.01      7.7±0.15ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.02     14.6±0.23ms        ? ?/sec    1.00     14.3±0.07ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.00     16.9±0.08ms        ? ?/sec    1.02     17.2±0.35ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.00     16.1±0.30ms        ? ?/sec    1.00     16.0±0.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.01      3.0±0.03ms        ? ?/sec    1.00      2.9±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.02     72.1±0.52ms        ? ?/sec    1.00     71.0±0.40ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.02     81.1±0.77ms        ? ?/sec    1.00     79.6±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.06    101.9±3.54ms        ? ?/sec    1.00     96.6±0.52ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.00    224.2±2.51ms        ? ?/sec    1.02    229.5±1.93ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.03     19.8±0.26ms        ? ?/sec    1.00     19.3±0.23ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.02     57.5±0.87ms        ? ?/sec    1.00     56.6±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.01     57.3±0.52ms        ? ?/sec    1.00     56.9±0.63ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.02     18.6±0.36ms        ? ?/sec    1.00     18.3±0.06ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.02     14.8±0.48ms        ? ?/sec    1.00     14.6±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.04      5.4±0.03ms        ? ?/sec    1.00      5.2±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.07     13.4±0.41ms        ? ?/sec    1.00     12.5±0.17ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     23.4±0.54ms        ? ?/sec    1.00     23.5±0.34ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.02      5.6±0.04ms        ? ?/sec    1.00      5.5±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.08      5.0±0.07ms        ? ?/sec    1.00      4.7±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.02      3.5±0.02ms        ? ?/sec    1.00      3.4±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.00    874.7±2.79µs        ? ?/sec    1.01    881.7±2.48µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.03      5.3±0.03ms        ? ?/sec    1.00      5.1±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.01      6.2±0.13ms        ? ?/sec    1.00      6.2±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.05     22.9±0.95ms        ? ?/sec    1.00     21.8±0.21ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     29.2±0.83ms        ? ?/sec    1.02     29.6±0.42ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     23.6±0.21ms        ? ?/sec    1.16     27.2±0.50ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.04      2.8±0.03ms        ? ?/sec    1.00      2.7±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.01    123.5±1.98ms        ? ?/sec    1.00    121.8±0.82ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.02     98.7±0.52ms        ? ?/sec    1.00     96.6±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.02    145.7±0.90ms        ? ?/sec    1.00    143.5±1.23ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.06   283.5±13.77ms        ? ?/sec    1.00    267.7±7.75ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.01     27.6±0.34ms        ? ?/sec    1.00     27.4±0.25ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.03    110.1±0.59ms        ? ?/sec    1.00    107.1±0.51ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.02    106.5±0.23ms        ? ?/sec    1.00    104.5±0.20ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.00     19.1±0.20ms        ? ?/sec    1.00     19.1±0.18ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.00     22.6±0.33ms        ? ?/sec    1.00     22.6±0.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.01      7.0±0.05ms        ? ?/sec    1.00      7.0±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.02     11.7±0.17ms        ? ?/sec    1.00     11.4±0.17ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.03     21.4±0.13ms        ? ?/sec    1.00     20.9±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.01      5.4±0.13ms        ? ?/sec    1.00      5.4±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.00      5.8±0.06ms        ? ?/sec    1.00      5.8±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.00      4.4±0.03ms        ? ?/sec    1.00      4.4±0.02ms        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 786.5s
Peak memory 3.1 GiB
Avg memory 2.9 GiB
CPU user 707.6s
CPU sys 78.7s
Disk read 0 B
Disk write 846.0 MiB

branch

Metric Value
Wall time 771.4s
Peak memory 3.2 GiB
Avg memory 3.1 GiB
CPU user 704.4s
CPU sys 66.8s
Disk read 0 B
Disk write 171.3 MiB

Measuring selectivity against the absolute result makes the threshold
less intuitive since it becomes more scattered after and_then. Revert
to measuring against the raw predicate result (relative to current
selection).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Dandandan
Copy link
Copy Markdown
Contributor Author

I've some ideas to improve this further

Instead of measuring selectivity (fraction of rows passing), measure
scattering: how much applying a predicate would fragment the selection.
A predicate is deferred if it would increase the selector count beyond
`current_selectors * scatter_threshold`.

This directly targets what makes fragmented selections expensive:
many small skip/read transitions during decoding.

- Rename selectivity_threshold -> scatter_threshold
- Add RowSelection::selector_count() (O(1) via Vec::len)
- Use selector count ratio instead of row selectivity ratio

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Linux bench-c4095977120-475-64bv9 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing selectivity_threshold (5f2be6e) to d53df60 (merge-base) diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
Results will be posted here when complete

@Dandandan Dandandan changed the title Filter pushdown selectivity threshold Add filter pushdown scatter threshold Mar 20, 2026
Instead of comparing selector count ratios, measure selector density:
selectors / total_rows. A density of 0.25 means at most 25 selectors
per 100 rows — anything more fragmented gets deferred.

This is more intuitive and directly proportional to the per-row cost
of skip/read transitions during decoding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Linux bench-c4096060759-476-hl5d8 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing selectivity_threshold (a9bc94f) to d53df60 (merge-base) diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
Results will be posted here when complete

Store total row count in RowSelection at construction time, enabling
O(1) total_row_count() instead of iterating all selectors. Also add
selector_count() for O(1) fragmentation measurement.

Update split_off() and limit() to maintain the cached row_count.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00   1081.2±5.61µs        ? ?/sec    1.00   1077.7±3.29µs        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00      6.6±0.03ms        ? ?/sec    1.00      6.5±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.01      7.6±0.05ms        ? ?/sec    1.00      7.6±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.01     14.3±0.04ms        ? ?/sec    1.00     14.1±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.01     16.8±0.06ms        ? ?/sec    1.00     16.7±0.08ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.01     15.8±0.04ms        ? ?/sec    1.00     15.7±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      3.0±0.02ms        ? ?/sec    1.01      3.1±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.18     84.1±9.60ms        ? ?/sec    1.00     71.5±0.15ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.27    106.1±2.62ms        ? ?/sec    1.00     83.3±0.16ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.00    134.2±5.81ms        ? ?/sec    1.18    158.4±1.65ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.03    246.7±2.46ms        ? ?/sec    1.00    240.0±1.32ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.01     19.2±0.09ms        ? ?/sec    1.00     19.0±0.06ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.02     58.1±0.22ms        ? ?/sec    1.00     56.7±0.18ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.02     58.1±0.31ms        ? ?/sec    1.00     56.9±0.15ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.01     18.5±0.07ms        ? ?/sec    1.00     18.3±0.07ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.12     15.1±0.20ms        ? ?/sec    1.00     13.4±0.10ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.19      5.4±0.02ms        ? ?/sec    1.00      4.6±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.08     13.3±0.19ms        ? ?/sec    1.00     12.3±0.11ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.05     24.6±0.33ms        ? ?/sec    1.00     23.4±0.21ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.12      5.7±0.03ms        ? ?/sec    1.00      5.1±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.11      5.0±0.02ms        ? ?/sec    1.00      4.5±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.08      3.6±0.02ms        ? ?/sec    1.00      3.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00   1065.7±2.65µs        ? ?/sec    1.00   1063.1±6.31µs        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00      6.5±0.02ms        ? ?/sec    1.01      6.5±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00      7.4±0.03ms        ? ?/sec    1.01      7.5±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.01     14.2±0.15ms        ? ?/sec    1.00     14.1±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.02     16.8±0.14ms        ? ?/sec    1.00     16.5±0.07ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.01     15.7±0.16ms        ? ?/sec    1.00     15.6±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      3.0±0.02ms        ? ?/sec    1.00      3.0±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.01     71.2±0.42ms        ? ?/sec    1.00     70.5±0.21ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.00     80.4±0.47ms        ? ?/sec    1.02     82.2±0.18ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.00     97.4±0.56ms        ? ?/sec    1.53    149.2±0.22ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.02    229.4±0.49ms        ? ?/sec    1.00    225.6±0.52ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.01     19.0±0.16ms        ? ?/sec    1.00     18.8±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.01     56.4±0.36ms        ? ?/sec    1.00     55.8±0.23ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.01     56.6±0.45ms        ? ?/sec    1.00     56.0±0.17ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.01     18.3±0.14ms        ? ?/sec    1.00     18.1±0.06ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.10     14.2±0.19ms        ? ?/sec    1.00     12.9±0.11ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.17      5.4±0.03ms        ? ?/sec    1.00      4.6±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.07     12.5±0.17ms        ? ?/sec    1.00     11.6±0.10ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.04     23.2±0.47ms        ? ?/sec    1.00     22.3±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.12      5.5±0.06ms        ? ?/sec    1.00      4.9±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.11      4.8±0.06ms        ? ?/sec    1.00      4.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.07      3.4±0.03ms        ? ?/sec    1.00      3.2±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.01   878.2±12.14µs        ? ?/sec    1.00    869.6±2.50µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.01      5.1±0.04ms        ? ?/sec    1.00      5.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.01      6.1±0.10ms        ? ?/sec    1.00      6.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.02     22.0±0.59ms        ? ?/sec    1.00     21.5±0.12ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     27.8±0.73ms        ? ?/sec    1.05     29.3±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     23.3±0.45ms        ? ?/sec    1.14     26.6±0.35ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.02      2.7±0.02ms        ? ?/sec    1.00      2.7±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.00    120.6±0.50ms        ? ?/sec    1.00    120.5±0.32ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.00     97.5±2.16ms        ? ?/sec    1.02     99.3±0.40ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.00    141.3±0.58ms        ? ?/sec    1.36    192.6±0.71ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.04   280.2±14.45ms        ? ?/sec    1.00   269.6±12.92ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.00     26.9±0.07ms        ? ?/sec    1.00     26.8±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.01    106.6±0.41ms        ? ?/sec    1.00    105.4±0.30ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.01    104.0±0.43ms        ? ?/sec    1.00    102.8±0.35ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.00     18.6±0.06ms        ? ?/sec    1.00     18.6±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.06     21.9±0.04ms        ? ?/sec    1.00     20.6±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.23      6.9±0.01ms        ? ?/sec    1.00      5.6±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.06     11.2±0.03ms        ? ?/sec    1.00     10.5±0.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.00     20.5±0.08ms        ? ?/sec    1.00     20.4±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.10      5.2±0.02ms        ? ?/sec    1.00      4.7±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.38      5.7±0.02ms        ? ?/sec    1.00      4.1±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.05      4.3±0.03ms        ? ?/sec    1.00      4.2±0.02ms        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 783.1s
Peak memory 3.1 GiB
Avg memory 2.9 GiB
CPU user 709.5s
CPU sys 73.4s
Disk read 0 B
Disk write 1.9 GiB

branch

Metric Value
Wall time 785.6s
Peak memory 3.2 GiB
Avg memory 3.1 GiB
CPU user 726.1s
CPU sys 59.6s
Disk read 0 B
Disk write 171.4 MiB

The total row count needed for scatter density calculation is already
available at both call sites (sync reader sums row group sizes, async
reader has row_count in scope). Pass it as a parameter instead of
storing it in RowSelection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00   1101.9±6.39µs        ? ?/sec    1.01   1107.6±8.29µs        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00      6.7±0.04ms        ? ?/sec    1.00      6.7±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.00      7.7±0.07ms        ? ?/sec    1.00      7.7±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.00     14.3±0.05ms        ? ?/sec    1.01     14.4±0.12ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.00     17.1±0.07ms        ? ?/sec    1.00     17.1±0.09ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.00     15.9±0.06ms        ? ?/sec    1.01     16.0±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      3.1±0.03ms        ? ?/sec    1.02      3.1±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.00     76.9±4.18ms        ? ?/sec    1.10     84.4±9.36ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.00     95.9±0.69ms        ? ?/sec    1.07    102.5±5.83ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.00    130.2±4.15ms        ? ?/sec    1.02    132.3±0.61ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.01    241.9±0.71ms        ? ?/sec    1.00    239.4±0.77ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.00     19.3±0.07ms        ? ?/sec    1.00     19.4±0.08ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.03     58.4±0.26ms        ? ?/sec    1.00     56.7±0.19ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.00     57.1±0.19ms        ? ?/sec    1.00     57.0±0.17ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.00     18.6±0.05ms        ? ?/sec    1.00     18.6±0.07ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.00     14.8±0.24ms        ? ?/sec    1.00     14.7±0.13ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.00      5.5±0.03ms        ? ?/sec    1.02      5.6±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.01     13.0±0.14ms        ? ?/sec    1.00     12.9±0.11ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.00     23.8±0.21ms        ? ?/sec    1.00     23.8±0.19ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.00      5.8±0.03ms        ? ?/sec    1.00      5.8±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.00      5.1±0.02ms        ? ?/sec    1.03      5.2±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.00      3.6±0.02ms        ? ?/sec    1.00      3.6±0.01ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00   1081.2±4.84µs        ? ?/sec    1.01  1093.5±14.06µs        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00      6.5±0.03ms        ? ?/sec    1.02      6.6±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00      7.5±0.04ms        ? ?/sec    1.00      7.5±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.00     14.2±0.04ms        ? ?/sec    1.01     14.3±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.00     16.8±0.07ms        ? ?/sec    1.00     16.8±0.07ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.00     15.8±0.04ms        ? ?/sec    1.00     15.8±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      3.0±0.02ms        ? ?/sec    1.00      3.0±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.02     72.0±0.54ms        ? ?/sec    1.00     70.8±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.02     80.8±0.48ms        ? ?/sec    1.00     79.3±0.22ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.03     99.7±0.73ms        ? ?/sec    1.00     96.6±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.03    221.4±0.41ms        ? ?/sec    1.00    215.4±1.56ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.00     19.0±0.10ms        ? ?/sec    1.01     19.2±0.13ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.02     56.9±0.48ms        ? ?/sec    1.00     55.9±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.00     56.3±0.18ms        ? ?/sec    1.00     56.1±0.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.00     18.3±0.05ms        ? ?/sec    1.01     18.4±0.08ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.01     14.2±0.22ms        ? ?/sec    1.00     14.1±0.22ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.00      5.4±0.01ms        ? ?/sec    1.01      5.4±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.00     12.5±0.18ms        ? ?/sec    1.00     12.4±0.23ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     22.5±0.17ms        ? ?/sec    1.01     22.7±0.25ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.00      5.5±0.03ms        ? ?/sec    1.01      5.6±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.00      4.9±0.02ms        ? ?/sec    1.03      5.0±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.00      3.4±0.01ms        ? ?/sec    1.01      3.5±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.00    872.5±5.37µs        ? ?/sec    1.01    879.4±1.75µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.00      5.2±0.04ms        ? ?/sec    1.00      5.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      6.1±0.02ms        ? ?/sec    1.01      6.2±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.02     22.1±0.60ms        ? ?/sec    1.00     21.7±0.12ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     27.9±0.75ms        ? ?/sec    1.05     29.4±0.14ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     23.0±0.06ms        ? ?/sec    1.15     26.6±0.35ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.01      2.7±0.02ms        ? ?/sec    1.00      2.7±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.02    122.6±0.46ms        ? ?/sec    1.00    119.8±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.02     98.0±0.35ms        ? ?/sec    1.00     95.9±0.22ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.01    142.5±0.50ms        ? ?/sec    1.00    141.6±0.64ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.00   276.3±13.33ms        ? ?/sec    1.00   277.0±14.52ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.00     27.0±0.06ms        ? ?/sec    1.01     27.1±0.15ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.02    107.6±0.46ms        ? ?/sec    1.00    105.5±0.62ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.01    103.4±0.38ms        ? ?/sec    1.00    102.4±0.29ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.01     18.7±0.05ms        ? ?/sec    1.00     18.6±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.00     21.9±0.05ms        ? ?/sec    1.00     22.0±0.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.00      6.9±0.04ms        ? ?/sec    1.01      7.0±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.00     11.2±0.04ms        ? ?/sec    1.00     11.2±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.00     20.5±0.06ms        ? ?/sec    1.01     20.7±0.23ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.00      5.2±0.02ms        ? ?/sec    1.01      5.3±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.00      5.6±0.04ms        ? ?/sec    1.01      5.7±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.00      4.3±0.02ms        ? ?/sec    1.01      4.4±0.02ms        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 779.4s
Peak memory 3.1 GiB
Avg memory 2.9 GiB
CPU user 710.1s
CPU sys 69.2s
Disk read 0 B
Disk write 2.0 GiB

branch

Metric Value
Wall time 782.1s
Peak memory 3.2 GiB
Avg memory 3.1 GiB
CPU user 711.4s
CPU sys 70.2s
Disk read 0 B
Disk write 171.4 MiB

@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

Based on ClickBench profiling, scattering predicates have densities
of 0.008-0.054 while clean predicates are <0.001. A threshold of 0.01
defers the scattering ones while applying the clean ones.

Also removes the eprintln debug instrumentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Dandandan
Copy link
Copy Markdown
Contributor Author

run benchmark arrow_reader_clickbench

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Linux bench-c4096287515-477-r5znv 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing selectivity_threshold (9cc2660) to d53df60 (merge-base) diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
Results will be posted here when complete

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark running (GKE) | trigger
Linux bench-c4096289927-478-9ltb4 6.12.55+ #1 SMP Sun Feb 1 08:59:41 UTC 2026 aarch64 GNU/Linux
Comparing selectivity_threshold (9cc2660) to d53df60 (merge-base) diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
Results will be posted here when complete

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.00   1090.2±4.95µs        ? ?/sec    1.00   1094.3±5.40µs        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.01      6.6±0.04ms        ? ?/sec    1.00      6.6±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.01      7.7±0.04ms        ? ?/sec    1.00      7.6±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.02     14.5±0.11ms        ? ?/sec    1.00     14.3±0.09ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.02     17.1±0.12ms        ? ?/sec    1.00     16.8±0.17ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.03     16.1±0.15ms        ? ?/sec    1.00     15.7±0.10ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      3.1±0.02ms        ? ?/sec    1.00      3.0±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.09     78.7±0.30ms        ? ?/sec    1.00     71.9±0.31ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.21     97.5±0.83ms        ? ?/sec    1.00     80.4±0.28ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.16    132.1±5.00ms        ? ?/sec    1.00    114.0±2.41ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.01    244.4±7.51ms        ? ?/sec    1.00    243.1±4.05ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.00     19.4±0.15ms        ? ?/sec    1.00     19.4±0.12ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.00     57.6±0.32ms        ? ?/sec    1.00     57.9±0.45ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.02     58.1±0.32ms        ? ?/sec    1.00     57.0±0.28ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.01     18.7±0.10ms        ? ?/sec    1.00     18.5±0.07ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.08     15.2±0.30ms        ? ?/sec    1.00     14.1±0.27ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.18      5.4±0.01ms        ? ?/sec    1.00      4.6±0.01ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.13     14.4±0.88ms        ? ?/sec    1.00     12.8±0.19ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.05     25.9±0.90ms        ? ?/sec    1.00     24.7±0.72ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.13      5.7±0.04ms        ? ?/sec    1.00      5.1±0.03ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.11      5.0±0.03ms        ? ?/sec    1.00      4.5±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.10      3.6±0.02ms        ? ?/sec    1.00      3.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00   1068.8±8.50µs        ? ?/sec    1.00   1071.6±3.39µs        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.08      7.1±0.18ms        ? ?/sec    1.00      6.6±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.05      7.9±0.13ms        ? ?/sec    1.00      7.5±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.07     15.1±0.13ms        ? ?/sec    1.00     14.1±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.06     17.8±0.22ms        ? ?/sec    1.00     16.9±0.21ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.04     16.4±0.14ms        ? ?/sec    1.00     15.8±0.12ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      2.9±0.02ms        ? ?/sec    1.00      2.9±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.00     71.0±0.49ms        ? ?/sec    1.00     71.2±0.36ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.00     80.2±0.59ms        ? ?/sec    1.00     80.0±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.00     97.5±1.21ms        ? ?/sec    1.02     99.7±3.72ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.05    232.8±1.81ms        ? ?/sec    1.00    221.0±0.58ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.00     19.2±0.14ms        ? ?/sec    1.00     19.2±0.16ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.00     56.2±0.38ms        ? ?/sec    1.01     56.9±0.36ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.02     57.5±0.45ms        ? ?/sec    1.00     56.5±0.31ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.02     18.4±0.13ms        ? ?/sec    1.00     18.1±0.08ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.06     14.4±0.24ms        ? ?/sec    1.00     13.6±0.20ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.18      5.3±0.01ms        ? ?/sec    1.00      4.5±0.01ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.05     12.7±0.21ms        ? ?/sec    1.00     12.0±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     23.4±0.45ms        ? ?/sec    1.00     23.3±0.44ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.11      5.5±0.02ms        ? ?/sec    1.00      4.9±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.10      4.8±0.02ms        ? ?/sec    1.00      4.4±0.02ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.08      3.4±0.01ms        ? ?/sec    1.00      3.2±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.01    876.8±3.83µs        ? ?/sec    1.00    868.7±2.14µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.01      5.1±0.02ms        ? ?/sec    1.00      5.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      6.1±0.02ms        ? ?/sec    1.00      6.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.03     22.1±0.60ms        ? ?/sec    1.00     21.5±0.14ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     28.3±0.80ms        ? ?/sec    1.04     29.4±0.29ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     23.3±0.09ms        ? ?/sec    1.15     26.9±0.43ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.04      2.7±0.03ms        ? ?/sec    1.00      2.6±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.01    123.2±0.38ms        ? ?/sec    1.00    122.3±0.73ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.01     98.1±0.25ms        ? ?/sec    1.00     96.8±0.30ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.00    142.8±0.36ms        ? ?/sec    1.01    144.2±0.72ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.05   282.5±16.04ms        ? ?/sec    1.00    268.5±7.96ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.02     27.2±0.13ms        ? ?/sec    1.00     26.6±0.12ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.01    107.2±0.99ms        ? ?/sec    1.00    105.9±0.40ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.04    106.8±0.17ms        ? ?/sec    1.00    102.9±0.35ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.03     19.0±0.25ms        ? ?/sec    1.00     18.6±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.09     22.5±0.09ms        ? ?/sec    1.00     20.7±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.18      6.9±0.01ms        ? ?/sec    1.00      5.9±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.01     11.2±0.05ms        ? ?/sec    1.00     11.2±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.03     20.9±0.26ms        ? ?/sec    1.00     20.4±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.00      5.2±0.03ms        ? ?/sec    1.09      5.7±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.11      5.6±0.03ms        ? ?/sec    1.00      5.1±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.00      4.4±0.02ms        ? ?/sec    1.01      4.5±0.01ms        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 782.8s
Peak memory 3.1 GiB
Avg memory 2.9 GiB
CPU user 707.0s
CPU sys 75.5s
Disk read 0 B
Disk write 2.1 GiB

branch

Metric Value
Wall time 763.2s
Peak memory 3.2 GiB
Avg memory 3.1 GiB
CPU user 697.7s
CPU sys 65.5s
Disk read 0 B
Disk write 171.4 MiB

@adriangbot
Copy link
Copy Markdown

🤖 Arrow criterion benchmark completed (GKE) | trigger

Details

group                                             main                                   selectivity_threshold
-----                                             ----                                   ---------------------
arrow_reader_clickbench/async/Q1                  1.01   1101.3±7.70µs        ? ?/sec    1.00   1090.2±9.59µs        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.01      6.8±0.26ms        ? ?/sec    1.00      6.8±0.24ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.00      7.9±0.28ms        ? ?/sec    1.00      7.9±0.25ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.01     15.1±0.24ms        ? ?/sec    1.00     14.9±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.03     17.6±0.32ms        ? ?/sec    1.00     17.2±0.38ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.01     16.3±0.39ms        ? ?/sec    1.00     16.1±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      3.1±0.06ms        ? ?/sec    1.00      3.1±0.06ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.24     89.7±1.27ms        ? ?/sec    1.00     72.1±0.54ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.29    104.9±1.85ms        ? ?/sec    1.00     81.1±0.40ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.19    134.5±4.84ms        ? ?/sec    1.00    112.7±2.82ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.02    245.1±2.54ms        ? ?/sec    1.00    240.6±2.28ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.02     20.0±0.39ms        ? ?/sec    1.00     19.6±0.41ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.01     59.0±0.26ms        ? ?/sec    1.00     58.3±0.33ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.02     58.9±0.77ms        ? ?/sec    1.00     57.7±0.63ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.01     18.9±0.26ms        ? ?/sec    1.00     18.7±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.06     14.8±0.44ms        ? ?/sec    1.00     14.0±0.47ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.18      5.5±0.10ms        ? ?/sec    1.00      4.6±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.03     13.3±0.32ms        ? ?/sec    1.00     12.9±0.35ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.00     24.1±0.18ms        ? ?/sec    1.01     24.4±0.50ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.10      5.7±0.11ms        ? ?/sec    1.00      5.2±0.10ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.09      5.0±0.07ms        ? ?/sec    1.00      4.6±0.07ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.09      3.6±0.05ms        ? ?/sec    1.00      3.3±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00   1074.5±6.25µs        ? ?/sec    1.00   1070.0±3.72µs        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00      6.7±0.20ms        ? ?/sec    1.00      6.7±0.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.03      8.0±0.14ms        ? ?/sec    1.00      7.8±0.25ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.00     14.7±0.35ms        ? ?/sec    1.00     14.7±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.02     17.3±0.46ms        ? ?/sec    1.00     16.9±0.45ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.03     16.4±0.43ms        ? ?/sec    1.00     15.9±0.37ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.00      3.0±0.05ms        ? ?/sec    1.03      3.1±0.06ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.01     71.9±0.59ms        ? ?/sec    1.00     71.2±0.60ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.01     81.1±0.64ms        ? ?/sec    1.00     80.1±0.50ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.01     97.8±1.02ms        ? ?/sec    1.00     96.8±0.88ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.00    221.8±2.38ms        ? ?/sec    1.04    229.5±6.69ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.03     20.1±0.35ms        ? ?/sec    1.00     19.5±0.43ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.00     57.3±0.69ms        ? ?/sec    1.00     57.2±0.52ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.01     57.5±0.98ms        ? ?/sec    1.00     57.2±0.53ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.01     18.5±0.29ms        ? ?/sec    1.00     18.3±0.23ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.08     14.5±0.50ms        ? ?/sec    1.00     13.4±0.59ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.20      5.5±0.09ms        ? ?/sec    1.00      4.6±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.05     12.9±0.32ms        ? ?/sec    1.00     12.3±0.44ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     23.0±0.41ms        ? ?/sec    1.03     23.7±0.30ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.12      5.6±0.12ms        ? ?/sec    1.00      5.0±0.15ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.12      4.9±0.08ms        ? ?/sec    1.00      4.4±0.09ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.09      3.5±0.05ms        ? ?/sec    1.00      3.2±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.02   886.2±16.66µs        ? ?/sec    1.00    871.8±2.41µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.01      5.2±0.06ms        ? ?/sec    1.00      5.2±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.01      6.2±0.07ms        ? ?/sec    1.00      6.1±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.02     22.2±0.44ms        ? ?/sec    1.00     21.8±0.28ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.00     24.8±0.43ms        ? ?/sec    1.21     30.1±0.82ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.00     23.6±0.38ms        ? ?/sec    1.16     27.3±0.56ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.00      2.7±0.05ms        ? ?/sec    1.00      2.7±0.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.01    123.9±0.74ms        ? ?/sec    1.00    122.2±1.15ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.01     98.1±1.01ms        ? ?/sec    1.00     97.4±0.94ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.00    144.0±2.14ms        ? ?/sec    1.01    145.0±1.88ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.04   280.2±13.85ms        ? ?/sec    1.00    270.6±7.87ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.01     27.5±0.55ms        ? ?/sec    1.00     27.2±0.47ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.01    108.0±1.05ms        ? ?/sec    1.00    107.2±0.84ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.02    106.3±0.87ms        ? ?/sec    1.00    104.3±0.51ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.01     19.4±0.05ms        ? ?/sec    1.00     19.2±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.05     22.3±0.41ms        ? ?/sec    1.00     21.2±0.41ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.18      7.0±0.09ms        ? ?/sec    1.00      5.9±0.07ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.00     11.4±0.22ms        ? ?/sec    1.00     11.5±0.19ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.00     21.0±0.34ms        ? ?/sec    1.01     21.1±0.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.00      5.3±0.09ms        ? ?/sec    1.12      5.9±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.10      5.7±0.08ms        ? ?/sec    1.00      5.2±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.00      4.4±0.08ms        ? ?/sec    1.03      4.5±0.06ms        ? ?/sec

Resource Usage

base (merge-base)

Metric Value
Wall time 789.1s
Peak memory 3.1 GiB
Avg memory 2.9 GiB
CPU user 712.6s
CPU sys 76.4s
Disk read 0 B
Disk write 2.0 GiB

branch

Metric Value
Wall time 767.8s
Peak memory 3.2 GiB
Avg memory 3.1 GiB
CPU user 699.9s
CPU sys 67.9s
Disk read 0 B
Disk write 171.3 MiB

Don't defer a predicate if applying it would reduce the selector count
(make the selection less fragmented). Only defer when the predicate
both increases selectors AND exceeds the density threshold.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
}
}

/// Set a scatter threshold for filter deferral.
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.

I like this even more now! This is now dealing with selector density, something that would be hard to do on the datafusion side and is correlated but not equivalent to overall filter selectivity, which I think is what probably ends up mattering more for coarser IO patterns and such given object store range coalescing, pages, etc.

Copy link
Copy Markdown
Contributor Author

@Dandandan Dandandan Mar 20, 2026

Choose a reason for hiding this comment

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

Yeah - I also think this is quite a bit better - I think it's OK if a filter "only" selects 50% of the rows, if it is nicely packed that will probably be able to skip almost 50% of the pages and lead to efficient IO and decoding.

But (especially when combining multiple filters), chances are the filter gets too fragmented, a 50% packed one is better than a 25% selective one that just does select 1 / skip 1 / select 1 and will do the same amount of IO and having horrible decoding performance.

I think you could go even go further and check which combination of filtera are giving the best of both worlds (selectivity and fragmentation)

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.

I think it's great, but this heuristic doesn't know anything about the distribution of data. Low selector density doesn't guarantee that skip/read transitions are large.

For example:

total_rows = 10_000
selector_count = 100
density = 100 / 10_000 = 0.01   (at threshold)

RowSelection (100 selectors total):
1)  select 4951 rows
2)  skip 1
3)  select 1
4)  skip 1
...
99) skip 1
100) select 4951 rows

Which wouldn't be good:

[ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ][XSXSXSXSXS...XS][ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ]
  ~4951 selected                                     98 rows            ~4951 selected

One way to catch this is by checking selectivity. 49 / 10_000 = 0.0049 (Very low)


I propose keeping both selector_density and selectivity_threshold you had before.

This matrix shows the possible cases:

Density (selectors/rows) Selectivity (skipped/rows) Typical Pattern Pushdown / Deferral Hint
Low Low Small contiguous skipped island Would think is good without checking the selectivity
Low High Large contiguous skips Great!
High Low Many tiny transitions, little skipped overall Worst case
High High Many tiny transitions but lots skipped Check if it increases the selector_count

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.

Makes sense!

/// produce a density above this value, its result is deferred.
/// For example, `0.25` allows at most 25 selectors per 100 rows.
///
/// A high selector density means many small skip/read transitions,
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.

Yes, but low selector density doesn't guarantee that skip/read transitions are large either.

}
}

/// Set a scatter threshold for filter deferral.
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.

I think it's great, but this heuristic doesn't know anything about the distribution of data. Low selector density doesn't guarantee that skip/read transitions are large.

For example:

total_rows = 10_000
selector_count = 100
density = 100 / 10_000 = 0.01   (at threshold)

RowSelection (100 selectors total):
1)  select 4951 rows
2)  skip 1
3)  select 1
4)  skip 1
...
99) skip 1
100) select 4951 rows

Which wouldn't be good:

[ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ][XSXSXSXSXS...XS][ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ]
  ~4951 selected                                     98 rows            ~4951 selected

One way to catch this is by checking selectivity. 49 / 10_000 = 0.0049 (Very low)


I propose keeping both selector_density and selectivity_threshold you had before.

This matrix shows the possible cases:

Density (selectors/rows) Selectivity (skipped/rows) Typical Pattern Pushdown / Deferral Hint
Low Low Small contiguous skipped island Would think is good without checking the selectivity
Low High Large contiguous skips Great!
High Low Many tiny transitions, little skipped overall Worst case
High High Many tiny transitions but lots skipped Check if it increases the selector_count

@sdf-jkl
Copy link
Copy Markdown
Contributor

sdf-jkl commented Mar 31, 2026

I also now have a very different idea.

Basically, why deal with averages around densities and selections, when we have the real numbers?

For selection materialization we loop through the selectors and count non-zero ones:

// total_rows: total number of rows selected / skipped
// effective_count: number of non-empty selectors
let (total_rows, effective_count) =
selection.iter().fold((0usize, 0usize), |(rows, count), s| {
if s.row_count > 0 {
(rows + s.row_count, count + 1)
} else {
(rows, count)
}
});

Why don't we count rows covered by long/short selectors instead?

// total_rows: total rows covered by selection
// effective_count: non-empty selector runs
// short_*_rows: rows in runs <= short_threshold
// long_*_rows: rows in runs >= long_threshold
let (
    total_rows,
    effective_count,
    short_select_rows,
    short_skip_rows,
    long_select_rows,
    long_skip_rows,
) = selection.iter().fold(
    (0usize, 0usize, 0usize, 0usize, 0usize, 0usize),
    |(rows, cnt, ss, sk, ls, lk), s| {
        if s.row_count == 0 {
            return (rows, cnt, ss, sk, ls, lk);
        }

        let rows = rows + s.row_count;
        let cnt = cnt + 1;
        let is_short = s.row_count <= short_threshold;
        let is_long = s.row_count >= long_threshold;

        match (s.skip, is_short, is_long) {
            (true, true, _) => (rows, cnt, ss, sk + s.row_count, ls, lk),
            (true, _, true) => (rows, cnt, ss, sk, ls, lk + s.row_count),
            (false, true, _) => (rows, cnt, ss + s.row_count, sk, ls, lk),
            (false, _, true) => (rows, cnt, ss, sk, ls + s.row_count, lk),
            _ => (rows, cnt, ss, sk, ls, lk), // middle bin
        }
    },
);

Where long/short_threshold would be based on the page size or something else?

With this statistics/histogram we'd be able to make a more data-driven decision on keeping or deferring the selection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parquet Changes to the parquet crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add selectivity threshold for filter pushdown

6 participants