Skip to content

Prune values across the query executor instead of on the calling thread - #19513

Open
xiangfu0 wants to merge 1 commit into
xiangfu0/data-3221-11-metadata-only-pruningfrom
xiangfu0/data-3221-12-parallel-value-pruning
Open

Prune values across the query executor instead of on the calling thread#19513
xiangfu0 wants to merge 1 commit into
xiangfu0/data-3221-11-metadata-only-pruningfrom
xiangfu0/data-3221-12-parallel-value-pruning

Conversation

@xiangfu0

@xiangfu0 xiangfu0 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

What

ValueBasedSegmentPruner now overrides prune(List, QueryContext, ExecutorService) and prunes across the query executor when there are enough segments to be worth it.

It previously implemented only the two-arg prune, so SegmentPruner's three-arg default silently discarded the executor it was handed. BloomFilterSegmentPruner already overrode it and pruned in parallel — the pruner that runs first, over the full segment set, did not.

The parallel path mirrors the bloom-filter one: strided tasks over the segment list, each with its own ValueCache and data-source cache (neither is thread-safe, and both are scoped to a single segment at a time regardless), run through QueryMultiThreadingUtils.runTasksWithDeadline so the query deadline and cancellation are honored. Below TARGET_NUM_SEGMENTS_PER_THREAD, or with no executor, it stays serial.

TARGET_NUM_SEGMENTS_PER_THREAD moves to the parent; BloomFilterSegmentPruner was shadowing it with the same value.

Why

This loop runs on the calling thread for every segment the server holds, before any per-segment parallelism starts. On a server holding 44,780 segments it is the longest single-threaded stretch of the query — and the default pruner chain is ColumnValueSegmentPruner, BloomFilterSegmentPruner, SelectionQuerySegmentPruner, so the serial one runs first and on the largest input.

Stacked on #19511, which removes the per-segment work in that loop (it was materializing a column to read min/max). This removes the serialisation. They are independent: either helps alone, and the combination is what makes pruning proportional to cores rather than to segments held.

Behaviour change

Segments come back in a different order than they went in. That is already true of BloomFilterSegmentPruner, which runs immediately after this pruner in the default chain, so nothing downstream can have depended on the input order surviving pruning.

Tests

ColumnValueSegmentPrunerTest#testParallelPruningSelectsTheSameSegments builds 40 segments — half matching the predicate, half prunable — and asserts the parallel path selects exactly the same set as the serial one. 52 pruner tests pass; spotless, checkstyle and license clean.

Stack

Part 12, based on #19511.

🤖 Generated with Claude Code

@xiangfu0 xiangfu0 added the performance Related to performance optimization label Sep 9, 2026
`ValueBasedSegmentPruner#prune` is a serial loop over every segment the
server holds, and it runs before any per-segment parallelism starts, so on a
server holding tens of thousands of segments it is a query's longest
single-threaded stretch.

It implemented only the two-arg `prune`, so `SegmentPruner`'s three-arg
default silently discarded the `ExecutorService` it was handed.
`BloomFilterSegmentPruner` already overrode that; the pruner that runs first,
over the full segment set, did not.

The parallel path mirrors the bloom-filter one: tasks over a strided slice of
the segments, each with its own value and data-source caches — neither is
thread-safe, and both are scoped to a single segment at a time regardless —
run through `QueryMultiThreadingUtils.runTasksWithDeadline` so the query
deadline and cancellation are honored. Below `TARGET_NUM_SEGMENTS_PER_THREAD`
segments, or with no executor, it stays serial.

Segments come back in a different order than they went in, which is already
true of the bloom-filter pruner that runs immediately after this one.

`TARGET_NUM_SEGMENTS_PER_THREAD` moves to the parent, where both pruners now
read the same value instead of the child shadowing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-12-parallel-value-pruning branch from 8c6e534 to 785926d Compare September 9, 2026 01:56
@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-11-metadata-only-pruning branch from 6f1c691 to 9a69689 Compare September 9, 2026 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Related to performance optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant