[improvement](be) Skip reading zonemap always-true columns for count on index#65242
[improvement](be) Skip reading zonemap always-true columns for count on index#65242mrhhsg wants to merge 2 commits into
Conversation
…on index
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: COUNT_ON_INDEX can still read predicate columns even when segment zone maps have proven all predicates on those columns are always true and removed them before SegmentIterator initialization. This makes count queries with range predicates over high-cardinality columns scan unnecessary column data. This change records columns whose predicates are fully removed by segment zone map pruning and lets SegmentIterator reuse the existing no-need-read path for non-output columns or COUNT_ON_INDEX columns, while preserving output and common-expression safeguards.
### Release note
None
### Check List (For Author)
- Test:
- Unit Test: ./run-be-ut.sh --run --filter=SegmentIteratorNoNeedReadDataTest.*
- Regression test: generated and verified fault_injection_p0/test_zonemap_always_true_count_on_index on a local single-node cluster
- Format: build-support/clang-format.sh; build-support/check-format.sh
- Static check: attempted build-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN, but clang-tidy could not analyze this checkout because the current toolchain reported 'stddef.h' file not found and a pre-existing clang-tidy-nolint issue in be/src/core/types.h
- Behavior changed: Yes. COUNT_ON_INDEX scans can skip data reads for predicate columns proven always true by segment zone maps.
- Does this need documentation: No
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
|
/review |
There was a problem hiding this comment.
Requesting changes for one correctness issue in the BE segment iterator path.
Checkpoint conclusions:
- Goal: the PR tries to skip physical data reads for predicate columns proven always true by segment zonemaps, especially for COUNT_ON_INDEX. The non-key path is covered, but the key-range path is not safe yet.
- Scope: the code change is small and focused, but it misses a parallel read path used by short-key range lookup.
- Concurrency/lifecycle/config/compatibility: no new concurrency, lifecycle, persistence, wire-format, or dynamic config concerns found.
- Data correctness: MAIN-001 is blocking. A key predicate removed by segment zonemap pruning can still leave the pushed key range active, and
_get_row_ranges_by_keys()can then compare default placeholder values instead of real key values. - Tests: the added BE unit test and fault-injection regression cover the intended non-key COUNT_ON_INDEX behavior, but not the key-column predicate plus pushed key-range ordering case.
- Performance/observability: the optimization goal is reasonable, and no extra observability requirement was found.
- User focus: no additional user-provided focus points were present.
Subagent conclusions:
tests-session-configproposed TSC-001; I verified it and accepted it as MAIN-001 for an inline comment.optimizer-rewriterecorded OR-DUP-001 as a duplicate confirmation of TSC-001; it was merged into MAIN-001.- Final convergence round 1 ended with both live subagents replying
NO_NEW_VALUABLE_FINDINGSfor the same current ledger/comment set.
Validation note: this runner is a static-review environment for this PR. .worktree_initialized, thirdparty/installed, and thirdparty/installed/bin/protoc are absent, so I did not run BE unit or regression tests here. Existing inline review threads were empty, so there were no duplicates to suppress.
| cid < _is_common_expr_column.size() && _is_common_expr_column[cid]; | ||
| const bool no_need_read_filter_column = | ||
| (_need_read_data_indices.contains(cid) && !_need_read_data_indices[cid]) || | ||
| (_opts.zonemap_always_true_pred_cols.contains(cid) && !used_by_common_expr); |
There was a problem hiding this comment.
This also affects key predicates. When a segment zonemap proves a key predicate always true, this code records the key cid in zonemap_always_true_pred_cols, but the original key_ranges are still present. _lazy_init() applies _get_row_ranges_by_keys() before lazy materialization setup, and the short-key binary search goes through _seek_and_peek() -> _seek_columns() / _read_columns(). Those now call _need_read_data() / _prune_column(), so a key cid in this set can be skipped and filled with default placeholders; _compare_short_key_with_seek_block() then compares the scan key against the placeholder instead of the real segment key.
For example, a DUP-key segment with key values [10, 20] and a pushed range k >= 5 AND k < 30 can have the k predicates removed as zonemap-always-true, while the short-key lookup still needs the real k values to compute row bounds. Please keep key-range seek reads independent of this zonemap no-read marker, or disable/remove the matching key range when the segment zonemap has already proven it fully true.
### What problem does this PR solve? Issue Number: None Related PR: apache#65242 Problem Summary: Segment zone map pruning can remove predicates that are always true for the current segment and mark those columns as no-need-read. Applying that marker to key columns is unsafe because key_ranges are still evaluated by short-key seeks before lazy materialization; the seek path must read real key values to compute row bounds. This change keeps the zonemap no-read marker restricted to non-key columns and adds coverage for a COUNT_ON_INDEX scan with an always-true key range predicate. ### Release note None ### Check List (For Author) - Test: - Unit Test: ./run-be-ut.sh --run --filter=SegmentIteratorNoNeedReadDataTest.* - Regression test: doris-local-regression --network 10.26.20.3/24 all -d fault_injection_p0 -s test_zonemap_always_true_count_on_index -forceGenOut - Regression test: doris-local-regression --network 10.26.20.3/24 all -d fault_injection_p0 -s test_zonemap_always_true_count_on_index - Format: build-support/clang-format.sh; build-support/check-format.sh - Static check: build-support/run-clang-tidy.sh --build-dir be/build_Release attempted, but failed on existing/toolchain diagnostics such as missing stddef.h and pre-existing clang-tidy warnings in changed files. - Behavior changed: Yes. Key columns are excluded from the segment zonemap no-read marker so key-range seeks always read real key values. - Does this need documentation: No
|
/review |
There was a problem hiding this comment.
Automated review completed for PR #65242 at head 7fc8fcdebba4989b5fc0c71f5956c08c877a67ff.
I did not find a new distinct inline issue to raise. The existing key-range concern is already covered by the live thread on SegmentIterator::_need_read_data(), and the current head addresses it by keeping key columns out of zonemap_always_true_pred_cols in Segment::new_iterator() and by checking !column.is_key() again in _need_read_data(). The added regression also covers the COUNT_ON_INDEX key-range case.
Critical checkpoint conclusions:
- Goal and test proof: the PR narrows data-page reads for non-key predicate columns whose segment zonemap predicates were already removed as always true. The changed BE unit test covers
_need_read_data()for non-key, key, output, and COUNT_ON_INDEX cases; the regression covers the non-key skip path and the key-range path. - Scope: the implementation is small and localized to
StorageReadOptions, segment iterator setup,_need_read_data(), and focused tests. - Concurrency/lifecycle: no new shared mutable state, locking, thread lifecycle, or persistent state is introduced.
- Compatibility/config: no new config item or protocol/storage-format change is introduced. Existing session flags are only used by tests.
- Parallel paths: key-range seeks, common-expression columns, output columns, delete predicates, and COUNT_ON_INDEX paths were checked. The key-column path is guarded after the existing review thread; common-expression and delete-predicate guards still force real reads.
- Tests/results: the new
.outmatches the addedqt_countandqt_count_with_key_rangetags. Its final blank separator matches the regression framework writer format and existing generated outputs, so I did not treatgit diff --check's generated-output blank-EOF warning as a useful inline review issue. - Observability/performance: no additional observability appears required for this small IO-skip optimization; the change removes unnecessary reads after segment-level predicate pruning.
User focus: no additional user-provided focus was present in .code-review.K2YjX4/review_focus.txt.
Subagent conclusions: optimizer-rewrite found no new candidate and marked the previous key-range issue as duplicate-covered by the existing thread. tests-session-config proposed TSC-1 for the generated .out final blank line; I dismissed it with framework/repository-format evidence. Convergence round 1 ended with both live subagents replying NO_NEW_VALUABLE_FINDINGS for the same ledger and empty proposed comment set.
Validation limits: this checkout is grafted/shallow, so GitHub PR file metadata was used as the authoritative six-file scope. .worktree_initialized, thirdparty/installed, and thirdparty/installed/bin/protoc are missing, and the available clang-format is version 18 rather than the required v16, so I did not run BE unit tests, regression tests, or repository clang-format locally.
|
run buildall |
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
|
PR approved by at least one committer and no changes requested. |
TPC-H: Total hot run time: 29772 ms |
TPC-DS: Total hot run time: 179995 ms |
ClickBench: Total hot run time: 25.15 s |
What problem does this PR solve?
Issue Number: None
Problem Summary:
COUNT_ON_INDEX can still read predicate columns even after segment zone maps have proven all predicates on those columns are always true and removed them before SegmentIterator initialization. This makes count queries with range predicates over high-cardinality columns scan unnecessary column data.
This PR records columns whose predicates are fully removed by segment zone map pruning, then lets SegmentIterator reuse the existing no-need-read path for non-output columns or COUNT_ON_INDEX columns. It keeps the existing output-column protection and adds a common-expression guard so expression materialization does not skip required data.
Release note
None
Check List (For Author)
./run-be-ut.sh --run --filter=SegmentIteratorNoNeedReadDataTest.*fault_injection_p0/test_zonemap_always_true_count_on_indexon a local single-node clusterbuild-support/clang-format.sh;build-support/check-format.shbuild-support/run-clang-tidy.sh --build-dir be/ut_build_ASAN, but clang-tidy could not analyze this checkout because the current toolchain reportedstddef.hfile not found and a pre-existingclang-tidy-nolintissue inbe/src/core/types.h