Skip to content

Comments

[Parquet] Support skipping pages with mask based evaluation#9118

Open
sdf-jkl wants to merge 46 commits intoapache:mainfrom
sdf-jkl:bitmask-skip-page
Open

[Parquet] Support skipping pages with mask based evaluation#9118
sdf-jkl wants to merge 46 commits intoapache:mainfrom
sdf-jkl:bitmask-skip-page

Conversation

@sdf-jkl
Copy link
Contributor

@sdf-jkl sdf-jkl commented Jan 9, 2026

Which issue does this PR close?

Rationale for this change

Check issue.

What changes are included in this PR?

  • Made next_mask_chunk page aware.

  • By adding page_offsets to ParquetRecordBatchReader

Are these changes tested?

Yes, unit tests

Are there any user-facing changes?

@github-actions github-actions bot added the parquet Changes to the parquet crate label Jan 9, 2026
@sdf-jkl sdf-jkl changed the title Bitmask skip page [Parquet] Support skipping pages with mask based evaluation Jan 9, 2026
@sdf-jkl sdf-jkl marked this pull request as ready for review January 9, 2026 20:41
@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Jan 9, 2026

@alamb, @hhhizzz, @tustvold please review when available.

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

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

Thank you @sdf-jkl -- this actually makes a lot of sense to me 👏

I have a few concerns:

  1. I am worried about the performance overhead of this approach (copying the page index and the loop for each batch) -- I will run some benchmarks to asses this
  2. I do wonder if we have test coverage for this entire situation -- in particular, do we have tests that repeatedly call next_mask_chunk after the first page and make sure we get the right rows?

If the performance looks good, I think we should add some more tests -- maybe @hhhizzz has some ideas on how to do this (or I think I can try and find some time to help out / work with codex to do so)

/// Using the row selection to skip(4), page2 won't be read at all, so in this
/// case we can't decode all the rows and apply a mask. To correctly apply the
/// bit mask, we need all 6 values be read, but page2 is not in memory.
fn override_selector_strategy_if_needed(
Copy link
Contributor

Choose a reason for hiding this comment

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

nice -- the idea is to avoid this function 👍

array_reader,
schema: Arc::new(schema),
read_plan,
page_offsets: page_offsets.map(|slice| Arc::new(slice.to_vec())),
Copy link
Contributor

Choose a reason for hiding this comment

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

So I think this will effectively will copy the entire OffsetIndexMetadataData structure (which I worry could be quite large)

I wonder if we need to find a way to avoid this (e.g. making the entire thing Arc'd in https://github.com/apache/arrow-rs/blob/67e04e758f1e62ec3d78d2f678daf433a4c54e30/parquet/src/file/metadata/mod.rs#L197-L196 somehow 🤔 )

Copy link
Contributor Author

@sdf-jkl sdf-jkl Jan 12, 2026

Choose a reason for hiding this comment

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

We could store only the &Vec<PageLocation> instead of the entire OffsetIndexMetadataData df9a493

while cursor < mask.len() && selected_rows < batch_size {
let mut page_end = mask.len();
if let Some(pages) = page_locations {
for loc in pages {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am also a little worried that this loop will take too long (it is O(N^2) in the number of pages as each time it looks through all pages

Maybe we could potentially add a PageLocationIterator to the cursor itself (so we know where to pick up)

Copy link
Contributor Author

@sdf-jkl sdf-jkl Jan 11, 2026

Choose a reason for hiding this comment

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

Maybe a binary search through a vec of page offsets? Would have to construct the vec once beforehand to keep us from rebuilding it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in df9a493

@alamb
Copy link
Contributor

alamb commented Jan 10, 2026

run benchmark arrow_reader_clickbench arrow_reader_row_filter

@alamb-ghbot
Copy link

🤖 ./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 bitmask-skip-page (5395dbf) to 964daec diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental --bench arrow_reader_clickbench
BENCH_FILTER=
BENCH_BRANCH_NAME=bitmask-skip-page
Results will be posted here when complete

@apache apache deleted a comment from alamb-ghbot Jan 10, 2026
@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                bitmask-skip-page                      main
-----                                -----------------                      ----
arrow_reader_clickbench/async/Q1     1.02      2.4±0.05ms        ? ?/sec    1.00      2.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q10    1.00     12.7±0.40ms        ? ?/sec    1.02     12.9±0.30ms        ? ?/sec
arrow_reader_clickbench/async/Q11    1.00     14.6±0.34ms        ? ?/sec    1.00     14.7±0.21ms        ? ?/sec
arrow_reader_clickbench/async/Q12    1.00     25.9±0.67ms        ? ?/sec    1.00     25.9±0.32ms        ? ?/sec
arrow_reader_clickbench/async/Q13    1.00     31.2±0.53ms        ? ?/sec    1.00     31.2±0.75ms        ? ?/sec
arrow_reader_clickbench/async/Q14    1.01     28.5±0.83ms        ? ?/sec    1.00     28.4±0.43ms        ? ?/sec
arrow_reader_clickbench/async/Q19    1.02      5.4±0.12ms        ? ?/sec    1.00      5.3±0.10ms        ? ?/sec
arrow_reader_clickbench/async/Q20    1.18    145.8±1.75ms        ? ?/sec    1.00    123.1±0.81ms        ? ?/sec
arrow_reader_clickbench/async/Q21    1.06    166.9±1.86ms        ? ?/sec    1.00    157.3±2.95ms        ? ?/sec
arrow_reader_clickbench/async/Q22    1.03   324.0±13.97ms        ? ?/sec    1.00    313.1±8.51ms        ? ?/sec
arrow_reader_clickbench/async/Q23    1.00    407.8±3.02ms        ? ?/sec    1.00    408.5±5.27ms        ? ?/sec
arrow_reader_clickbench/async/Q24    1.00     34.2±0.38ms        ? ?/sec    1.00     34.1±0.40ms        ? ?/sec
arrow_reader_clickbench/async/Q27    1.00    100.6±1.00ms        ? ?/sec    1.00    100.2±1.29ms        ? ?/sec
arrow_reader_clickbench/async/Q28    1.01     99.0±0.92ms        ? ?/sec    1.00     98.3±0.69ms        ? ?/sec
arrow_reader_clickbench/async/Q30    1.01     30.7±0.58ms        ? ?/sec    1.00     30.5±0.64ms        ? ?/sec
arrow_reader_clickbench/async/Q36    1.01    109.3±0.58ms        ? ?/sec    1.00    108.5±0.67ms        ? ?/sec
arrow_reader_clickbench/async/Q37    1.00     85.0±1.17ms        ? ?/sec    1.00     84.8±0.39ms        ? ?/sec
arrow_reader_clickbench/async/Q38    1.00     32.9±0.47ms        ? ?/sec    1.00     32.8±0.30ms        ? ?/sec
arrow_reader_clickbench/async/Q39    1.00     46.2±0.47ms        ? ?/sec    1.00     46.4±0.40ms        ? ?/sec
arrow_reader_clickbench/async/Q40    1.02     27.8±0.60ms        ? ?/sec    1.00     27.2±0.49ms        ? ?/sec
arrow_reader_clickbench/async/Q41    1.00     22.4±0.72ms        ? ?/sec    1.00     22.5±0.35ms        ? ?/sec
arrow_reader_clickbench/async/Q42    1.01     11.1±0.09ms        ? ?/sec    1.00     11.1±0.30ms        ? ?/sec
arrow_reader_clickbench/sync/Q1      1.01      2.1±0.04ms        ? ?/sec    1.00      2.1±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q10     1.00      9.8±0.07ms        ? ?/sec    1.01      9.9±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q11     1.00     11.4±0.25ms        ? ?/sec    1.00     11.4±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q12     1.03     35.0±1.40ms        ? ?/sec    1.00     34.0±0.45ms        ? ?/sec
arrow_reader_clickbench/sync/Q13     1.00     38.8±0.55ms        ? ?/sec    1.24     48.0±1.00ms        ? ?/sec
arrow_reader_clickbench/sync/Q14     1.00     36.2±0.60ms        ? ?/sec    1.22     44.4±0.59ms        ? ?/sec
arrow_reader_clickbench/sync/Q19     1.02      4.4±0.02ms        ? ?/sec    1.00      4.3±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q20     1.00    177.0±2.01ms        ? ?/sec    1.01    177.9±0.95ms        ? ?/sec
arrow_reader_clickbench/sync/Q21     1.00    234.5±2.00ms        ? ?/sec    1.01    236.3±2.21ms        ? ?/sec
arrow_reader_clickbench/sync/Q22     1.00    479.1±3.47ms        ? ?/sec    1.01    483.5±4.64ms        ? ?/sec
arrow_reader_clickbench/sync/Q23     1.02   444.0±13.03ms        ? ?/sec    1.00   436.1±13.35ms        ? ?/sec
arrow_reader_clickbench/sync/Q24     1.00     44.8±0.67ms        ? ?/sec    1.03     46.1±0.41ms        ? ?/sec
arrow_reader_clickbench/sync/Q27     1.00    155.2±1.67ms        ? ?/sec    1.00    155.1±1.40ms        ? ?/sec
arrow_reader_clickbench/sync/Q28     1.00    149.6±1.04ms        ? ?/sec    1.00    149.8±1.04ms        ? ?/sec
arrow_reader_clickbench/sync/Q30     1.01     31.4±0.43ms        ? ?/sec    1.00     31.1±0.56ms        ? ?/sec
arrow_reader_clickbench/sync/Q36     1.00    153.8±1.14ms        ? ?/sec    1.00    154.0±1.38ms        ? ?/sec
arrow_reader_clickbench/sync/Q37     1.00     87.9±1.08ms        ? ?/sec    1.01     88.9±0.72ms        ? ?/sec
arrow_reader_clickbench/sync/Q38     1.00     29.1±0.39ms        ? ?/sec    1.01     29.4±0.24ms        ? ?/sec
arrow_reader_clickbench/sync/Q39     1.00     33.9±0.42ms        ? ?/sec    1.00     34.0±0.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q40     1.00     26.6±0.33ms        ? ?/sec    1.00     26.6±0.60ms        ? ?/sec
arrow_reader_clickbench/sync/Q41     1.01     29.1±0.61ms        ? ?/sec    1.00     28.8±0.33ms        ? ?/sec
arrow_reader_clickbench/sync/Q42     1.00     12.7±0.10ms        ? ?/sec    1.00     12.6±0.08ms        ? ?/sec

@alamb-ghbot
Copy link

🤖 ./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 bitmask-skip-page (5395dbf) to 964daec diff
BENCH_NAME=arrow_reader_row_filter
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental --bench arrow_reader_row_filter
BENCH_FILTER=
BENCH_BRANCH_NAME=bitmask-skip-page
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                                                                bitmask-skip-page                      main
-----                                                                                -----------------                      ----
arrow_reader_row_filter/float64 <= 99.0/all_columns/async                            1.00  1711.1±12.59µs        ? ?/sec    1.01  1725.2±10.04µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/all_columns/sync                             1.00  1807.9±10.76µs        ? ?/sec    1.03  1865.4±19.96µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/async                  1.00  1571.9±23.10µs        ? ?/sec    1.02  1607.7±31.74µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/sync                   1.00  1548.3±27.08µs        ? ?/sec    1.02  1575.1±27.17µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/async              1.00   1528.8±7.49µs        ? ?/sec    1.01  1548.4±19.21µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/sync               1.00  1673.9±17.01µs        ? ?/sec    1.02  1699.9±13.19µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/async    1.00  1354.8±20.42µs        ? ?/sec    1.01  1361.8±13.37µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/sync     1.00  1348.2±12.04µs        ? ?/sec    1.01   1363.6±9.07µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/async                             1.00  1719.1±21.06µs        ? ?/sec    1.00   1712.1±8.82µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/sync                              1.00  1808.9±15.74µs        ? ?/sec    1.01  1829.3±13.16µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/async                   1.00  1571.7±13.46µs        ? ?/sec    1.00  1572.2±11.69µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/sync                    1.00  1534.2±12.04µs        ? ?/sec    1.01  1552.9±10.49µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/async                              1.00    918.8±8.99µs        ? ?/sec    1.03   943.7±38.25µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/sync                               1.00   864.1±17.34µs        ? ?/sec    1.02   878.3±16.94µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/async                    1.00    839.9±5.83µs        ? ?/sec    1.02    855.1±8.58µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/sync                     1.00    848.7±5.97µs        ? ?/sec    1.03    870.4±9.58µs        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/async                                 1.27      3.5±0.06ms        ? ?/sec    1.00      2.8±0.03ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/sync                                  1.00      3.6±0.04ms        ? ?/sec    1.00      3.6±0.04ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/async                       1.02      2.6±0.02ms        ? ?/sec    1.00      2.6±0.03ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/sync                        1.00      2.3±0.03ms        ? ?/sec    1.00      2.3±0.06ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/async                                  1.00  1957.2±24.32µs        ? ?/sec    1.01  1972.9±32.45µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/sync                                   1.00      2.0±0.02ms        ? ?/sec    1.01      2.1±0.04ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/async                        1.00  1809.3±44.74µs        ? ?/sec    1.00  1807.9±16.81µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/sync                         1.00  1797.3±13.53µs        ? ?/sec    1.01  1810.9±31.64µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/async                                 1.00  1249.1±15.21µs        ? ?/sec    1.03  1283.2±13.68µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/sync                                  1.00   1252.4±9.50µs        ? ?/sec    1.03  1289.5±11.20µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/async                       1.00  1128.0±13.41µs        ? ?/sec    1.03   1157.9±7.78µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/sync                        1.00   1138.9±9.11µs        ? ?/sec    1.03  1172.3±40.63µs        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/async                             1.02      3.3±0.04ms        ? ?/sec    1.00      3.2±0.03ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/sync                              1.02      3.6±0.02ms        ? ?/sec    1.00      3.6±0.04ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/async                   1.01      2.8±0.01ms        ? ?/sec    1.00      2.8±0.01ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/sync                    1.00      2.5±0.02ms        ? ?/sec    1.00      2.5±0.07ms        ? ?/sec

@Dandandan
Copy link
Contributor

run benchmark arrow_reader_clickbench arrow_reader_row_filter

@alamb-ghbot
Copy link

🤖 ./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 bitmask-skip-page (6919196) to 964daec diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental --bench arrow_reader_clickbench
BENCH_FILTER=
BENCH_BRANCH_NAME=bitmask-skip-page
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                bitmask-skip-page                      main
-----                                -----------------                      ----
arrow_reader_clickbench/async/Q1     1.01      2.3±0.03ms        ? ?/sec    1.00      2.3±0.02ms        ? ?/sec
arrow_reader_clickbench/async/Q10    1.00     12.7±0.48ms        ? ?/sec    1.00     12.7±0.19ms        ? ?/sec
arrow_reader_clickbench/async/Q11    1.00     14.3±0.39ms        ? ?/sec    1.01     14.4±0.35ms        ? ?/sec
arrow_reader_clickbench/async/Q12    1.02     25.7±0.75ms        ? ?/sec    1.00     25.2±0.50ms        ? ?/sec
arrow_reader_clickbench/async/Q13    1.02     31.3±0.57ms        ? ?/sec    1.00     30.8±0.52ms        ? ?/sec
arrow_reader_clickbench/async/Q14    1.03     28.4±0.63ms        ? ?/sec    1.00     27.7±0.24ms        ? ?/sec
arrow_reader_clickbench/async/Q19    1.00      5.3±0.06ms        ? ?/sec    1.00      5.3±0.12ms        ? ?/sec
arrow_reader_clickbench/async/Q20    1.00    142.9±2.30ms        ? ?/sec    1.03    147.1±6.53ms        ? ?/sec
arrow_reader_clickbench/async/Q21    1.00    164.3±1.11ms        ? ?/sec    1.08    177.8±2.83ms        ? ?/sec
arrow_reader_clickbench/async/Q22    1.02    317.8±9.85ms        ? ?/sec    1.00   310.7±35.18ms        ? ?/sec
arrow_reader_clickbench/async/Q23    1.00    402.9±3.18ms        ? ?/sec    1.02    412.2±2.91ms        ? ?/sec
arrow_reader_clickbench/async/Q24    1.03     34.7±0.65ms        ? ?/sec    1.00     33.7±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q27    1.00     98.0±0.64ms        ? ?/sec    1.03    100.9±0.60ms        ? ?/sec
arrow_reader_clickbench/async/Q28    1.00     98.4±0.54ms        ? ?/sec    1.02    100.0±1.22ms        ? ?/sec
arrow_reader_clickbench/async/Q30    1.00     30.7±0.35ms        ? ?/sec    1.00     30.6±0.87ms        ? ?/sec
arrow_reader_clickbench/async/Q36    1.00    108.0±1.62ms        ? ?/sec    1.02    109.7±0.79ms        ? ?/sec
arrow_reader_clickbench/async/Q37    1.00     84.3±0.75ms        ? ?/sec    1.02     86.1±0.61ms        ? ?/sec
arrow_reader_clickbench/async/Q38    1.00     32.7±0.28ms        ? ?/sec    1.01     33.1±0.42ms        ? ?/sec
arrow_reader_clickbench/async/Q39    1.00     46.3±0.48ms        ? ?/sec    1.00     46.4±0.49ms        ? ?/sec
arrow_reader_clickbench/async/Q40    1.02     28.3±0.49ms        ? ?/sec    1.00     27.7±0.34ms        ? ?/sec
arrow_reader_clickbench/async/Q41    1.03     23.1±0.69ms        ? ?/sec    1.00     22.4±0.43ms        ? ?/sec
arrow_reader_clickbench/async/Q42    1.02     11.3±0.10ms        ? ?/sec    1.00     11.1±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q1      1.00      2.1±0.01ms        ? ?/sec    1.00      2.1±0.01ms        ? ?/sec
arrow_reader_clickbench/sync/Q10     1.00      9.8±0.18ms        ? ?/sec    1.00      9.8±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q11     1.04     11.7±0.39ms        ? ?/sec    1.00     11.3±0.21ms        ? ?/sec
arrow_reader_clickbench/sync/Q12     1.11     36.2±1.97ms        ? ?/sec    1.00     32.5±0.39ms        ? ?/sec
arrow_reader_clickbench/sync/Q13     1.00     40.0±0.55ms        ? ?/sec    1.15     45.9±0.73ms        ? ?/sec
arrow_reader_clickbench/sync/Q14     1.00     37.0±0.59ms        ? ?/sec    1.15     42.5±0.81ms        ? ?/sec
arrow_reader_clickbench/sync/Q19     1.03      4.4±0.05ms        ? ?/sec    1.00      4.3±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q20     1.00    172.6±1.37ms        ? ?/sec    1.02    176.7±1.89ms        ? ?/sec
arrow_reader_clickbench/sync/Q21     1.00    230.7±2.59ms        ? ?/sec    1.01    233.5±3.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q22     1.00    474.0±5.22ms        ? ?/sec    1.01    478.3±3.39ms        ? ?/sec
arrow_reader_clickbench/sync/Q23     1.00   440.5±13.95ms        ? ?/sec    1.00   442.2±17.34ms        ? ?/sec
arrow_reader_clickbench/sync/Q24     1.05     46.7±1.35ms        ? ?/sec    1.00     44.5±0.50ms        ? ?/sec
arrow_reader_clickbench/sync/Q27     1.00    153.1±1.65ms        ? ?/sec    1.01    154.2±0.97ms        ? ?/sec
arrow_reader_clickbench/sync/Q28     1.01    151.2±2.35ms        ? ?/sec    1.00    149.2±1.16ms        ? ?/sec
arrow_reader_clickbench/sync/Q30     1.09     32.8±0.69ms        ? ?/sec    1.00     30.0±0.60ms        ? ?/sec
arrow_reader_clickbench/sync/Q36     1.00    149.7±1.66ms        ? ?/sec    1.03    154.7±1.74ms        ? ?/sec
arrow_reader_clickbench/sync/Q37     1.00     86.4±0.84ms        ? ?/sec    1.03     89.0±1.67ms        ? ?/sec
arrow_reader_clickbench/sync/Q38     1.00     28.3±0.46ms        ? ?/sec    1.03     29.2±0.28ms        ? ?/sec
arrow_reader_clickbench/sync/Q39     1.00     32.7±0.34ms        ? ?/sec    1.04     33.9±0.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q40     1.00     26.3±0.28ms        ? ?/sec    1.00     26.3±0.25ms        ? ?/sec
arrow_reader_clickbench/sync/Q41     1.01     29.1±0.32ms        ? ?/sec    1.00     28.7±0.29ms        ? ?/sec
arrow_reader_clickbench/sync/Q42     1.00     12.6±0.24ms        ? ?/sec    1.01     12.7±0.43ms        ? ?/sec

@alamb-ghbot
Copy link

🤖 ./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 bitmask-skip-page (6919196) to 964daec diff
BENCH_NAME=arrow_reader_row_filter
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental --bench arrow_reader_row_filter
BENCH_FILTER=
BENCH_BRANCH_NAME=bitmask-skip-page
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                                                                bitmask-skip-page                       main
-----                                                                                -----------------                       ----
arrow_reader_row_filter/float64 <= 99.0/all_columns/async                            1.00  1737.0±24.43µs        ? ?/sec     1.00  1740.6±12.25µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/all_columns/sync                             1.00  1841.2±16.88µs        ? ?/sec     1.00  1850.3±15.17µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/async                  1.00  1595.2±23.94µs        ? ?/sec     1.00  1589.8±11.48µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/sync                   1.00  1554.2±18.65µs        ? ?/sec     1.02  1579.9±11.57µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/async              1.00  1550.7±10.67µs        ? ?/sec     1.01  1570.4±22.51µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/sync               1.00  1710.2±13.28µs        ? ?/sec     1.02  1748.2±19.70µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/async    1.00  1378.1±20.68µs        ? ?/sec     1.01  1388.9±17.42µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/sync     1.00  1377.8±10.71µs        ? ?/sec     1.00  1382.7±12.99µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/async                             1.01  1740.5±14.97µs        ? ?/sec     1.00  1725.8±18.37µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/sync                              1.00  1842.9±13.91µs        ? ?/sec     1.00  1837.5±16.92µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/async                   1.00  1596.0±16.08µs        ? ?/sec     1.00  1593.0±20.88µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/sync                    1.00  1557.3±14.67µs        ? ?/sec     1.01  1575.3±26.16µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/async                              1.01    922.3±8.84µs        ? ?/sec     1.00    911.4±9.30µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/sync                               1.01   864.8±12.31µs        ? ?/sec     1.00   852.6±12.39µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/async                    1.02   851.8±17.05µs        ? ?/sec     1.00    835.0±7.01µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/sync                     1.01   855.7±10.16µs        ? ?/sec     1.00   848.3±26.47µs        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/async                                 1.00      2.7±0.02ms        ? ?/sec     1.42      3.9±0.04ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/sync                                  1.00      3.6±0.08ms        ? ?/sec     1.06      3.8±0.17ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/async                       1.00      2.6±0.04ms        ? ?/sec     1.01      2.7±0.11ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/sync                        1.00      2.3±0.03ms        ? ?/sec     1.05      2.4±0.06ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/async                                  1.00  1967.4±107.56µs        ? ?/sec    1.02      2.0±0.03ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/sync                                   1.00      2.0±0.01ms        ? ?/sec     1.02      2.1±0.06ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/async                        1.00  1772.0±11.49µs        ? ?/sec     1.02  1804.6±13.86µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/sync                         1.00  1783.5±17.77µs        ? ?/sec     1.01  1808.2±11.79µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/async                                 1.00  1257.4±13.21µs        ? ?/sec     1.02   1277.2±8.80µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/sync                                  1.00  1275.4±11.35µs        ? ?/sec     1.00  1270.5±14.14µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/async                       1.00  1162.3±13.90µs        ? ?/sec     1.00  1157.2±23.30µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/sync                        1.02  1172.1±10.33µs        ? ?/sec     1.00  1152.2±21.33µs        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/async                             1.00      3.3±0.03ms        ? ?/sec     1.00      3.3±0.04ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/sync                              1.00      3.6±0.05ms        ? ?/sec     1.01      3.6±0.02ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/async                   1.00      2.8±0.02ms        ? ?/sec     1.01      2.8±0.08ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/sync                    1.00      2.5±0.01ms        ? ?/sec     1.01      2.6±0.03ms        ? ?/sec

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Jan 13, 2026

@alamb @Dandandan clickbench q12, 24, 30 show some degradation, but everything else looks like an overall improvement.


let reader = ParquetRecordBatchReader::new(array_reader, plan);
let reader =
ParquetRecordBatchReader::new(array_reader, plan, page_offsets.cloned());
Copy link
Contributor

Choose a reason for hiding this comment

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

cloned may cause extra expense here, can we use Arc<[PageLocation]> to avoid that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a big api change to make PageLocation or OffsetIndexMetadataData an Arc inside ParquetMetaData.

If we'd want to make that change, I can open an issue and work up a PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @hhhizzz that copying the offsets here is not good

I thought about it some more, and I think the reason the copy is currently needed is that the decision of should the page be skipped is postponed until the next MaskChunk is needed

One potential idea I had to avoid this, is to use the page index in the ReadPlanBuilder when building, rather than pass in the page index to every call for next_batch.

So maybe that would look something like extending MaskCursor from

/// Cursor for iterating a mask-backed [`RowSelection`]
///
/// This is best for dense selections where there are many small skips
/// or selections. For example, selecting every other row.
#[derive(Debug)]
pub struct MaskCursor {
    mask: BooleanBuffer,
    /// Current absolute offset into the selection
    position: usize,
}

To also track what ranges should be skipped entirely. Maybe something like

#[derive(Debug)]
pub struct MaskCursor {
    mask: BooleanBuffer,
    /// Current absolute offset into the selection
    position: usize,
    /// Which row ranges should be skipped entirely?
    skip_ranges: Vec<Range<usize>>,
}

That I think would simplify the logic for next_mask_chunk significantly and it would avoid the need to copy the entire page inde

@hhhizzz
Copy link
Contributor

hhhizzz commented Jan 14, 2026

Thank you! @sdf-jkl , the code look great, just wondering if we could add more Unit tests.

@hhhizzz
Copy link
Contributor

hhhizzz commented Jan 14, 2026

Here's the exists test:

async fn test_row_filter_full_page_skip_is_handled_async() {

I think we can just add one more UT to test the skipping page with RowSelectionPolicy set to Mask instead of Auto

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Jan 30, 2026

I want to write down my thoughts about this issue, hopefully it will be helpful.

The original issue:

  • Without falling back to RLE selectors, mask-based selection can fetch data from not loaded pages(skipped pages).

The simplest case where this happens is:

  1. A previous selection is contiguous enough to skip a full page in a column.
  2. Another selection is added to the first one and materializes as a mask selection. (Could be in the same 1st selection)
  3. Data is read using mask selection, and we receive an error: attempting to fetch data that was not loaded.

The case above is pretty simple and does not require different page layouts between columns. It only requires a skipped page in a column and a mask selection.

This can happen:

  • during the filter evaluation stage
  • while reading projections (selections coming from filters or manually created)
  • during both stages

This was fixed by:

  • introducing page awareness to the reader.

The new issue (introduced in #9239):

  • Page awareness needs to be column-aware across all projected columns. Col A's page layout may differ from col B's. This can lead to mask chunk including part of a page skipped in one column, resulting in the same error: attempting to fetch data that was not loaded.

Prerequisites for this to happen:

  • selection that skips a page in at least one projected column
  • different page layouts between columns in projection(plan or predicate)
  • ?

How we fixed? it:

  • Clip each mask chunk at the closest upcoming page boundary to the current cursor (across all columns)
  • Together with the initial skip inside the mask chunk, this prevents us from reading any page that was skipped by the selection.
  • Initial skip also helps coalesce skipped pages without reading them one by one.

Possible positions where mask cursor can end up:

  • At the start of a skipped page
  • At the start of a loaded page
  • In the middle of a loaded page
  • It cannot start in the middle of a skipped page, because that case would be handled by the initial skip

Cases where this issue could happen:

  • During filter evaluation, if page is skipped (although we usually evaluate only the single column required for an ArrowPredicate)
  • During the final read phase (multiple columns with different page offsets)

Invariant enforced by the fix:
A mask chunk must not span across a page boundary in any column.

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Jan 30, 2026

So, the test cases we need for the new issue are:

  • manually created selectors that skip a page and mask-based materialized. No filters needed. Final projection with multiple columns with different page layouts.
  • Filters create an RLE selection first, that later becomes mask-based. try different cols with different page layouts for applying mask-based selection. The final projection can be one col (other than predicate ones) to make this test more focused. ArrowPredicates with multiple columns in projection would be great.
  • An end-to-end test that tests both different col predicates and different col final projection.

alamb pushed a commit that referenced this pull request Feb 5, 2026
# Which issue does this PR close?

<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax.
-->

Push after #9354 where `TestReader` is moved to a common place for other
async reader tests.

- Part of #9348.
- Will help with #9118

# Rationale for this change

<!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.
-->

# What changes are included in this PR?
- Move sync tests from `parquet/tests/arrow_reader/row_filter.rs` to
`parquet/tests/arrow_reader/row_filter/sync.rs`
- Move async tests from `parquet/src/async_reader/mod.rs` to
`parquet/tests/arrow_reader/row_filter/async.rs`

<!--
There is no need to duplicate the description in the issue here but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->

# Are these changes tested?
Code movement
<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code

If tests are not included in your PR, please explain why (for example,
are they covered by existing tests)?
-->

# Are there any user-facing changes?
Code movement
<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.

If there are any breaking changes to public APIs, please call them out.
-->
@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 5, 2026

image

With the tests moved this should be more readable

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 11, 2026

@alamb Above I argue that the only page‑offset issues can appear during filter reads or final reads.

During filtering, it can happen when an ArrowPredicate projects multiple columns.

During the final read, it can happen for when multiple columns are projected.

In both cases the columns need have different page offsets (due to types, encodings, or other reasons) to cause errors.

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 13, 2026

I have one more idea I want to try this weekend💭

Copy link
Contributor Author

@sdf-jkl sdf-jkl left a comment

Choose a reason for hiding this comment

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

@alamb
The change I was thinking about is this:
Instead of using all page offsets as MaskChunk boundaries, only use the skipped pages.

Previously, we treated every page offsets as a boundary. When reading loaded pages, this meant we had to stop at every page and start a new MaskChunk, which introduced a significant function calls overhead. Skipped pages would coalesce because, once we start a new MaskChunk, consecutive values from the start of the mask are zeros, so they merge into the initial skip.

By using only skipped pages as boundaries for MaskChunks, we stop a chunk only when the next page is not loaded. This way, skipped pages are still coalesce through the initial skip, but loaded pages are no longer bounded by every page offset and can coalesce until they reach a skipped page.

This should prevent the back and forth MaskChunk calls at every original page boundary in the projection.


/// Returns true if selectors should be forced, preventing mask materialisation
pub(crate) fn should_force_selectors(
/// Returns row offsets for the starts of skipped pages across projected columns
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Function to retrieve row offsets for skipped pages across projected columns.

mask: BooleanBuffer,
/// Current absolute offset into the selection
position: usize,
/// Index of the next page boundary candidate. This advances monotonically
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Make MaskCursor know next boundary index like the idea in sdf-jkl#2

// or until the mask is exhausted. This mirrors the behaviour of the legacy
// `RowSelector` queue-based iteration.
while cursor < mask.len() && selected_rows < batch_size {
let max_chunk_rows = page_boundaries
Copy link
Contributor Author

@sdf-jkl sdf-jkl Feb 16, 2026

Choose a reason for hiding this comment

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

This way we can avoid binary search in every MaskChunk

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 17, 2026

@tustvold Could you take a look? (You reviewed #8733 and mentioned page skipping support)

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 18, 2026

@Dandandan could you run the benchmark again since this could be related to apache/datafusion#20324

@Dandandan
Copy link
Contributor

Dandandan commented Feb 19, 2026

@Dandandan could you run the benchmark again since this could be related to apache/datafusion#20324

(I think the runner is stuck again)
run benchmark arrow_reader_clickbench

@Dandandan
Copy link
Contributor

run benchmark arrow_reader_clickbench

@Dandandan
Copy link
Contributor

@alamb

@Dandandan
Copy link
Contributor

I'll check out the benchmark locally

@Dandandan
Copy link
Contributor

Dandandan commented Feb 19, 2026

For arrow_reader_clickbench the benchmarks seem roughly on par with main (so not an improvement using the static filters in the benchmark)

@alamb-ghbot
Copy link

🤖 ./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 bitmask-skip-page (2111012) 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=bitmask-skip-page
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                             bitmask-skip-page                      main
-----                                             -----------------                      ----
arrow_reader_clickbench/async/Q1                  1.00      2.3±0.03ms        ? ?/sec    1.01      2.3±0.05ms        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00     10.4±0.10ms        ? ?/sec    1.01     10.5±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.01     12.0±0.31ms        ? ?/sec    1.00     11.9±0.13ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.01     21.9±0.26ms        ? ?/sec    1.00     21.8±0.64ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.02     27.4±0.44ms        ? ?/sec    1.00     26.9±0.16ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.01     24.4±0.28ms        ? ?/sec    1.00     24.1±0.22ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.02      5.2±0.05ms        ? ?/sec    1.00      5.2±0.04ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.00    111.4±0.62ms        ? ?/sec    1.29    144.1±0.95ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.00   154.5±12.34ms        ? ?/sec    1.07    166.0±1.09ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.00   202.0±19.50ms        ? ?/sec    1.06   213.3±12.31ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.00    403.9±7.37ms        ? ?/sec    1.00    403.7±2.56ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.02     30.5±0.35ms        ? ?/sec    1.00     30.0±0.42ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.00     96.8±1.26ms        ? ?/sec    1.01     98.0±0.93ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.00     95.3±0.36ms        ? ?/sec    1.02     96.8±0.89ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.01     26.8±0.39ms        ? ?/sec    1.00     26.5±0.37ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.00     27.4±0.15ms        ? ?/sec    1.08     29.4±0.36ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.00      8.7±0.04ms        ? ?/sec    1.11      9.7±0.09ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.00     24.4±0.26ms        ? ?/sec    1.05     25.6±0.22ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.00     42.8±0.41ms        ? ?/sec    1.02     43.8±0.27ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.00     10.6±0.14ms        ? ?/sec    1.31     13.9±0.15ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.00      9.0±0.15ms        ? ?/sec    1.19     10.7±0.16ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.00      5.9±0.04ms        ? ?/sec    1.00      5.9±0.08ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.00      2.3±0.02ms        ? ?/sec    1.01      2.3±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00      9.9±0.18ms        ? ?/sec    1.02     10.1±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00     11.3±0.36ms        ? ?/sec    1.02     11.5±0.15ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.00     21.3±0.40ms        ? ?/sec    1.01     21.5±0.25ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.00     26.2±0.39ms        ? ?/sec    1.00     26.2±0.22ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.00     23.7±0.16ms        ? ?/sec    1.01     24.0±0.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.01      5.0±0.02ms        ? ?/sec    1.00      4.9±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.00    106.8±0.57ms        ? ?/sec    1.01    108.0±0.71ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.00    119.2±0.53ms        ? ?/sec    1.01    120.8±1.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.00    147.2±0.84ms        ? ?/sec    1.01    148.6±1.33ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.02    359.9±2.22ms        ? ?/sec    1.00    353.1±5.47ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.00     29.0±0.74ms        ? ?/sec    1.02     29.6±0.44ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.00     92.3±0.65ms        ? ?/sec    1.02     94.1±0.91ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.00     91.2±0.59ms        ? ?/sec    1.01     92.0±0.46ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.01     25.8±0.32ms        ? ?/sec    1.00     25.5±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.00     24.7±0.28ms        ? ?/sec    1.05     26.1±0.22ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.00      8.5±0.05ms        ? ?/sec    1.09      9.3±0.09ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.00     21.8±0.34ms        ? ?/sec    1.04     22.5±0.29ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     37.5±0.52ms        ? ?/sec    1.02     38.4±0.27ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.00      9.9±0.13ms        ? ?/sec    1.29     12.8±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.00      8.5±0.24ms        ? ?/sec    1.15      9.8±0.05ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.03      5.7±0.06ms        ? ?/sec    1.00      5.5±0.03ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.01  1987.9±54.73µs        ? ?/sec    1.00   1976.0±9.92µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.00      7.5±0.08ms        ? ?/sec    1.02      7.6±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      8.9±0.19ms        ? ?/sec    1.00      8.9±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.00     27.9±0.33ms        ? ?/sec    1.11     30.9±1.90ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.09     41.5±0.82ms        ? ?/sec    1.00     38.2±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.01     30.4±0.32ms        ? ?/sec    1.00     30.0±0.13ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.02      4.2±0.03ms        ? ?/sec    1.00      4.1±0.02ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.00    170.5±1.14ms        ? ?/sec    1.01    172.0±1.45ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.00    127.0±0.86ms        ? ?/sec    1.01    127.7±0.88ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.00    200.5±1.58ms        ? ?/sec    1.00    201.2±1.21ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.00   415.9±15.76ms        ? ?/sec    1.05   434.6±15.55ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.05     40.0±0.42ms        ? ?/sec    1.00     38.0±0.42ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.00    147.2±1.06ms        ? ?/sec    1.01    148.5±1.13ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.00    142.3±1.11ms        ? ?/sec    1.01    143.4±0.93ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.04     27.2±0.25ms        ? ?/sec    1.00     26.2±0.27ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.00     31.4±0.17ms        ? ?/sec    1.02     32.0±0.64ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.01     10.5±0.03ms        ? ?/sec    1.00     10.4±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.00     17.5±0.27ms        ? ?/sec    1.00     17.6±0.22ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.00     29.6±0.21ms        ? ?/sec    1.03     30.6±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.03      9.1±0.04ms        ? ?/sec    1.00      8.8±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.01      9.3±0.03ms        ? ?/sec    1.00      9.1±0.06ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.01      6.8±0.02ms        ? ?/sec    1.00      6.7±0.07ms        ? ?/sec

@sdf-jkl
Copy link
Contributor Author

sdf-jkl commented Feb 23, 2026

@Dandandan @alamb

arrow_reader_clickbench/async/Q20                 1.00    111.4±0.62ms        ? ?/sec    1.29    144.1±0.95ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.00      8.7±0.04ms        ? ?/sec    1.11      9.7±0.09ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.00     10.6±0.14ms        ? ?/sec    1.31     13.9±0.15ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.00      9.0±0.15ms        ? ?/sec    1.19     10.7±0.16ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.00      9.9±0.13ms        ? ?/sec    1.29     12.8±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.00      8.5±0.24ms        ? ?/sec    1.15      9.8±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.00     27.9±0.33ms        ? ?/sec    1.11     30.9±1.90ms        ? ?/sec

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.

[Parquet] Support skipping pages with mask based evaluation

5 participants