Skip to content

Conversation

@alamb
Copy link
Contributor

@alamb alamb commented Dec 28, 2025

Which issue does this PR close?

Rationale for this change

While working on apache/datafusion#19477, and profiling ClickBench q7, I noticed that the RowSelectors was being cloned to resolve the strategy -- for a large number of selections this is expensive and shows up in the traces

Screenshot 2025-12-28 at 4 49 49 PM
samply record -- ./datafusion-cli-alamb_enable_pushdown  -f q.sql  > /dev/null  2>&

We should change the code to avoid cloning the RowSelectors when resolving the strategy.

Changes

Don't clone / allocate while resolving the strategy.

I don't expect this to have a massive impact, but it did show up in the profile

FYI @hhhizzz -- perhaps you could review this PR

Are these changes tested?

Yes by CI

Are there any user-facing changes?

small performance improvement

@github-actions github-actions bot added the parquet Changes to the parquet crate label Dec 28, 2025
@alamb alamb changed the title Avoid a clone while resolving the read plan [parquet] Avoid a clone while resolving the read strategy Dec 28, 2025
None => return RowSelectionStrategy::Selectors,
};

let trimmed = selection.clone().trim();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this clone shows up in the traces for some of the clickbench queries. I think this is because there are 9000 selectors for these queries

@alamb alamb marked this pull request as ready for review December 28, 2025 22:10
let total_rows: usize = selectors.iter().map(|s| s.row_count).sum();
let selector_count = selectors.len();
if selector_count == 0 {
let non_empty_selector_count = selection.iter().filter(|s| s.row_count > 0).count();
Copy link
Contributor

Choose a reason for hiding this comment

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

Good improvement! I didn’t notice this in my benchmarks, likely because the dataset was too small.
Small suggestion:

  • non_empty_selector_count is too long, effective_count could sound better.
  • Using fold to replace 2 seperate iteration might be better.
let (total_rows, effective_count) = selection.iter()
    .fold((0, 0), |(rows, count), s| {
        if s.row_count > 0 {
            (rows + s.row_count, count + 1)
        } else {
            (rows, count)
        }
    });

if effective_count == 0 {
    return RowSelectionStrategy::Mask;
}

if total_rows < effective_count.saturating_mul(threshold) {
    RowSelectionStrategy::Mask
} else {
    RowSelectionStrategy::Selectors
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a great idea -- done in fe10c50

@alamb

This comment was marked as outdated.

@apache apache deleted a comment from alamb-ghbot Dec 29, 2025
@alamb-ghbot

This comment was marked as outdated.

@alamb-ghbot

This comment was marked as outdated.

@alamb-ghbot

This comment was marked as outdated.

@alamb-ghbot

This comment was marked as outdated.

@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 alamb/no_clone (fe10c50) to 814ee42 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=alamb_no_clone
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                                                                alamb_no_clone                         main
-----                                                                                --------------                         ----
arrow_reader_row_filter/float64 <= 99.0/all_columns/async                            1.00  1717.9±21.18µs        ? ?/sec    1.01  1733.6±13.50µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/all_columns/sync                             1.00  1848.2±58.94µs        ? ?/sec    1.02  1878.8±16.06µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/async                  1.00  1589.9±10.21µs        ? ?/sec    1.01  1602.1±21.82µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/sync                   1.00  1556.0±11.98µs        ? ?/sec    1.02  1583.0±15.97µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/async              1.00  1542.2±22.49µs        ? ?/sec    1.00  1540.2±16.29µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/sync               1.00  1692.5±22.82µs        ? ?/sec    1.01  1717.4±17.10µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/async    1.00  1359.5±14.32µs        ? ?/sec    1.02  1390.4±20.35µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/sync     1.00  1355.4±18.98µs        ? ?/sec    1.03   1389.8±9.26µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/async                             1.00  1727.8±11.94µs        ? ?/sec    1.00  1732.5±23.19µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/sync                              1.00  1841.8±20.19µs        ? ?/sec    1.01  1862.8±43.35µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/async                   1.00  1570.8±15.73µs        ? ?/sec    1.01  1591.6±21.48µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/sync                    1.00  1559.3±16.49µs        ? ?/sec    1.02  1583.4±10.58µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/async                              1.02   939.5±11.59µs        ? ?/sec    1.00    916.9±6.24µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/sync                               1.01   870.7±13.35µs        ? ?/sec    1.00   864.9±13.22µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/async                    1.02    858.4±8.44µs        ? ?/sec    1.00    843.3±8.55µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/sync                     1.01    860.8±6.02µs        ? ?/sec    1.00    849.0±8.76µs        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/async                                 1.00      2.7±0.03ms        ? ?/sec    1.01      2.8±0.04ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/sync                                  1.00      3.6±0.08ms        ? ?/sec    1.02      3.7±0.07ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/async                       1.00      2.6±0.04ms        ? ?/sec    1.03      2.7±0.03ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/sync                        1.00      2.3±0.02ms        ? ?/sec    1.03      2.4±0.02ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/async                                  1.00  1961.5±13.12µs        ? ?/sec    1.00  1961.6±12.92µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/sync                                   1.00      2.1±0.03ms        ? ?/sec    1.01      2.1±0.01ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/async                        1.00  1792.4±25.91µs        ? ?/sec    1.01  1802.2±30.89µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/sync                         1.00  1802.1±24.29µs        ? ?/sec    1.00  1806.8±33.10µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/async                                 1.00  1268.1±20.28µs        ? ?/sec    1.00   1267.0±7.65µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/sync                                  1.00  1294.9±17.64µs        ? ?/sec    1.00   1294.0±8.32µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/async                       1.00  1162.0±12.80µs        ? ?/sec    1.00  1158.1±10.63µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/sync                        1.00  1165.7±11.63µs        ? ?/sec    1.00  1160.0±10.21µs        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/async                             1.00      3.2±0.03ms        ? ?/sec    1.00      3.2±0.03ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/sync                              1.00      3.7±0.04ms        ? ?/sec    1.00      3.6±0.06ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/async                   1.01      2.8±0.07ms        ? ?/sec    1.00      2.8±0.02ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/sync                    1.00      2.5±0.03ms        ? ?/sec    1.00      2.5±0.03ms        ? ?/sec

@alamb
Copy link
Contributor Author

alamb commented Dec 30, 2025

run benchmark 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 alamb/no_clone (fe10c50) to 814ee42 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=alamb_no_clone
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                                                                alamb_no_clone                         main
-----                                                                                --------------                         ----
arrow_reader_row_filter/float64 <= 99.0/all_columns/async                            1.00  1719.9±14.04µs        ? ?/sec    1.00  1724.5±17.65µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/all_columns/sync                             1.00  1839.9±10.51µs        ? ?/sec    1.01  1850.1±18.11µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/async                  1.00  1579.3±18.65µs        ? ?/sec    1.01  1595.8±24.76µs        ? ?/sec
arrow_reader_row_filter/float64 <= 99.0/exclude_filter_column/sync                   1.00  1569.4±10.69µs        ? ?/sec    1.00  1571.9±10.44µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/async              1.00  1531.1±14.17µs        ? ?/sec    1.01  1545.6±28.85µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/all_columns/sync               1.00  1702.0±15.67µs        ? ?/sec    1.00  1696.6±12.64µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/async    1.00  1366.3±11.39µs        ? ?/sec    1.00  1367.4±24.23µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0 AND ts >= 9000/exclude_filter_column/sync     1.02   1380.2±9.42µs        ? ?/sec    1.00  1356.5±13.41µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/async                             1.00  1715.5±15.24µs        ? ?/sec    1.00  1723.6±15.66µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/all_columns/sync                              1.00  1838.8±16.17µs        ? ?/sec    1.01  1857.2±20.10µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/async                   1.00  1580.1±10.29µs        ? ?/sec    1.01  1595.3±25.23µs        ? ?/sec
arrow_reader_row_filter/float64 > 99.0/exclude_filter_column/sync                    1.00  1566.4±35.42µs        ? ?/sec    1.00  1568.2±15.89µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/async                              1.00    914.2±7.99µs        ? ?/sec    1.02    933.6±6.12µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/all_columns/sync                               1.00    857.4±7.47µs        ? ?/sec    1.04   892.7±11.34µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/async                    1.00   844.6±11.90µs        ? ?/sec    1.03   872.8±12.79µs        ? ?/sec
arrow_reader_row_filter/int64 == 9999/exclude_filter_column/sync                     1.00    857.1±7.33µs        ? ?/sec    1.03    884.1±5.25µs        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/async                                 1.00      2.8±0.06ms        ? ?/sec    1.01      2.8±0.03ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/all_columns/sync                                  1.01      3.6±0.08ms        ? ?/sec    1.00      3.6±0.03ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/async                       1.00      2.7±0.06ms        ? ?/sec    1.01      2.7±0.02ms        ? ?/sec
arrow_reader_row_filter/int64 > 90/exclude_filter_column/sync                        1.00      2.4±0.02ms        ? ?/sec    1.00      2.4±0.03ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/async                                  1.01      2.0±0.03ms        ? ?/sec    1.00  1997.3±10.98µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/all_columns/sync                                   1.02      2.1±0.05ms        ? ?/sec    1.00      2.1±0.02ms        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/async                        1.00  1827.9±12.44µs        ? ?/sec    1.01  1843.2±11.06µs        ? ?/sec
arrow_reader_row_filter/ts < 9000/exclude_filter_column/sync                         1.00  1839.6±12.58µs        ? ?/sec    1.00  1846.1±12.03µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/async                                 1.00  1255.1±20.74µs        ? ?/sec    1.02  1274.8±18.54µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/all_columns/sync                                  1.00   1272.8±7.22µs        ? ?/sec    1.03  1309.7±11.59µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/async                       1.00  1154.9±13.53µs        ? ?/sec    1.03   1185.7±9.57µs        ? ?/sec
arrow_reader_row_filter/ts >= 9000/exclude_filter_column/sync                        1.00   1158.2±7.62µs        ? ?/sec    1.02   1187.0±9.14µs        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/async                             1.01      3.3±0.06ms        ? ?/sec    1.00      3.3±0.06ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/all_columns/sync                              1.02      3.7±0.07ms        ? ?/sec    1.00      3.7±0.03ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/async                   1.00      2.8±0.03ms        ? ?/sec    1.01      2.8±0.05ms        ? ?/sec
arrow_reader_row_filter/utf8View <> ''/exclude_filter_column/sync                    1.00      2.6±0.02ms        ? ?/sec    1.00      2.6±0.02ms        ? ?/sec

@alamb
Copy link
Contributor Author

alamb commented Jan 5, 2026

@hhhizzz do you think this PR is ready to merge?

@hhhizzz
Copy link
Contributor

hhhizzz commented Jan 5, 2026

@hhhizzz do you think this PR is ready to merge?

Yeah, I think its ready to merge.

@alamb
Copy link
Contributor Author

alamb commented Jan 5, 2026

@hhhizzz do you think this PR is ready to merge?

Yeah, I think its ready to merge.

Thank you for the review ❤️

@alamb alamb merged commit b8a2c1a into apache:main Jan 5, 2026
16 checks passed
@alamb alamb deleted the alamb/no_clone branch January 5, 2026 18:39
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 performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants