Doris-Breakwater commented on issue #67995:
URL: https://github.com/apache/doris/issues/67995#issuecomment-5675539557

   ## Initial maintainer analysis
   
   **Triage:** This is a high-confidence correctness issue from static analysis 
of the reported snapshot `846d9b2ebfc595ddfd77579447db16a674c901f7`. It is not 
merely a missed optimization: a physical zone map is being used to decide the 
truth of predicates over a different, read-time value. The issue currently has 
no labels or assignee; the appropriate classification is the repository's 
bug/correctness label plus the BE storage/segment (zone-map) area.
   
   ### Verified facts
   
   - Expression zone-map pruning is enabled by default 
(`SessionVariable.enableExprZonemapFilter = true`; the BE helper also treats an 
unset query option as enabled).
   - `build_segment_zonemap_context` reads the physical `ColumnReader` summary, 
and `SegmentIterator::_apply_expr_zonemap_to_row_ranges` does the same for page 
summaries. Neither path recognizes read-time-substituted columns. Their only 
safety gate is `Segment::can_apply_predicate_safely`, whose implementation only 
handles variant target-type compatibility and returns `true` for these BIGINT 
columns.
   - The reported placeholder/substitution mismatch is present:
     - `__DORIS_BINLOG_TSO__` is written as NULL by 
`fill_binlog_system_columns`, then replaced with a non-NULL 
`commit_tso.end_tso()` (or `0` for `-1`) for single-version `read_row_binlog` 
reads.
     - `__DORIS_VERSION_COL__` has default `0`, then 
`SegmentIterator::_replace_version_col_if_needed` replaces it with 
`version.second` for single-version rowsets.
     - `__DORIS_COMMIT_TSO_COL__` has default `0`; the intended read path 
requests a `ConstantColumnReader` carrying the assigned commit TSO for a 
single-version rowset.
   - Row-level evaluation occurs after `_replace_version_col_if_needed` and 
`_update_tso_col_if_needed`, while segment/page zone-map pruning occurs before 
those substitutions. This establishes the semantic disagreement in the code 
path.
   - An all-NULL binlog-TSO zone map makes comparison evaluators return 
`kNoMatch` immediately and makes `IS NOT NULL` return `kNoMatch`, so an 
expression over the read-time non-NULL value can eliminate a whole segment/page.
   - The version-column reachability analysis is also supported by the 
snapshot: the hidden column is enabled by default for UNIQUE KEY tables without 
sequence mapping, uses aggregation `NONE` for merge-on-write and `REPLACE` for 
merge-on-read, is included in `LogicalOlapScan` output via 
`getBaseSchema(true)`, and explicit slot binding does not reject an invisible 
column. Existing regression suites explicitly reference this column.
   
   There is an additional wrong-result mode beyond the false negatives 
described in the issue. After creating the iterator, `Segment::new_iterator` 
calls `ColumnReader::prune_predicates_by_zone_map` on cached readers without a 
placeholder-column guard. For a single-version rowset whose semantic version is 
positive, the physical `[0, 0]` summary can mark a range predicate such as 
`__DORIS_VERSION_COL__ < 1` as always true; the predicate is then removed even 
though it is false for the substituted value. That can admit nonmatching rows. 
The fix and tests should therefore cover both “no-match” pruning and 
“always-true” predicate removal.
   
   ### Scope and related issue
   
   - The unsafe synthesized-value cases are limited by the same guards as their 
substitutions: single-version rowsets for version/commit TSO, and additionally 
`read_row_binlog` for binlog TSO. Range/compaction rowsets and non-binlog reads 
of `__DORIS_BINLOG_TSO__` must continue using physical values.
   - The commit-TSO expression path is entangled with #67994 but this issue is 
not a duplicate. The expression builder can cache a non-constant reader before 
`new_column_iterator` requests the constant, while #67994 shows that the cache 
key ignores the requested constant. Fixing only the cache does not make the 
binlog-TSO or version physical zone maps safe; fixing only the zone-map 
builders does not repair a previously cached wrong reader.
   - A nearby path should be audited before closing this issue: 
`segment_zone_maps_can_answer_agg` excludes the commit-TSO ordinal but not the 
version/binlog-TSO ordinals, and `VStatisticsIterator` reads MIN/MAX from zone 
maps. I have not established FE reachability for a pushed MIN/MAX over these 
hidden columns, so this is a test requirement/hypothesis rather than a 
confirmed additional symptom.
   
   ### Missing runtime evidence
   
   The reporter explicitly states that the SQL was not run. Static evidence is 
strong enough to accept the issue, but the PR should include runtime 
confirmation with:
   
   1. The exact SQL output using concrete returned version values (replace the 
`<a version from above>` placeholder), `SHOW CREATE TABLE`/full schema output, 
and the exact build SHA.
   2. `EXPLAIN VERBOSE` proving whether each predicate is a `ColumnPredicate` 
or a pushed common expression, plus a query profile containing 
`RowsStatsFiltered`, `ExprZoneMapFilteredSegments`, and 
`ExprZoneMapFilteredPages` where applicable.
   3. Rowset/segment topology proving the tested data remains in single-version 
rowsets (avoid a compaction race), and a range/compacted-rowset control case.
   4. For the TSO cases, the exact row-binlog read entry point, 
`read_row_binlog` state, assigned commit TSO, pushed expression shape, and 
results with `enable_expr_zonemap_filter` both on and off.
   
   Note that `SET enable_expr_zonemap_filter = false` is only a partial 
diagnostic/workaround: it disables the expression path, not the version 
column's `ColumnPredicate` zone-map path or the post-creation predicate-removal 
path.
   
   ### Recommended implementation and tests
   
   Centralize the concept of an **effective read-time zone map** for 
placeholder-backed columns, with the same conditions used by the substitution 
code. For an active substitution, expose a non-NULL degenerate summary (`min = 
max = semantic value`, `has_not_null = true`, `has_null = false`): 
`version.second` for the version column and the effective commit TSO 
(`end_tso`, or `0` where current read semantics use `0`) for the TSO columns. 
Otherwise use the physical summary. This helper should be consumed consistently 
by:
   
   - segment-level expression zone-map evaluation;
   - page-level expression evaluation (the value is segment-constant, so every 
page has the same effective summary, or physical page pruning can be 
conservatively skipped);
   - segment/page `ColumnPredicate` pruning, including the existing binlog-TSO 
special case and the missing version case; and
   - the post-creation `prune_predicates_by_zone_map` optimization.
   
   Also audit statistics-iterator and any dictionary/bloom/index pruning of 
these columns so no other physical summary can make a semantic decision about a 
substituted value.
   
   Tests should include: version equality/range predicates that exercise both 
false-negative pruning and false-positive predicate removal; expression 
comparisons and `IS NULL`/`IS NOT NULL`; all three placeholder columns; segment 
and page paths; assigned and `-1` TSO; `read_row_binlog` true/false; 
single-version versus range rowsets; merge-on-write versus merge-on-read; and 
cache call ordering coordinated with #67994. Each positive query should compare 
pruning enabled/disabled where that switch applies and assert returned rows, 
not only pruning counters.
   
   Breakwater-GitHub-Analysis-Slot: slot_1e4d5197b1b3
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to