Skip to content

[opt](nereids) scale num_nulls in col stats when partition pruned - #62265

Merged
englefly merged 2 commits into
apache:masterfrom
englefly:partition-null-num
Apr 22, 2026
Merged

[opt](nereids) scale num_nulls in col stats when partition pruned#62265
englefly merged 2 commits into
apache:masterfrom
englefly:partition-null-num

Conversation

@englefly

@englefly englefly commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

For an OlapTable, when only a subset of partitions is selected, the num_nulls value in column statistics needs to be scaled proportionally.
Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

…um_nulls value in column statistics needs to be scaled proportionally.
@englefly

englefly commented Apr 9, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@Thearas

Thearas commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@englefly

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 14.29% (1/7) 🎉
Increment coverage report
Complete coverage report

@englefly

Copy link
Copy Markdown
Contributor Author

/review

@englefly

Copy link
Copy Markdown
Contributor Author

run nonConcurrent

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking findings:

  • StatsCalculator.computeOlapScan() now rescales numNulls even when getColumnStatistic(..., selectedPartitionNames) has already returned the merged stats for exactly the selected partitions. With enable_partition_analyze=true, that undercounts nulls by the prune ratio and feeds wrong stats into IS NULL / join estimation.
  • The added regression only covers the fallback-to-table-stats path and misses the partition-stats-enabled path where the regression occurs.

Critical checkpoints:

  • Goal of change: scale numNulls for partition-pruned scans when only table-level column stats are available. Current code only partially accomplishes this: it fixes the fallback path but breaks the exact partition-stats path. The new regression proves the fallback case only.
  • Minimality: The patch is small, but the unconditional rescaling is broader than needed. It should be limited to the table-level fallback path.
  • Concurrency: No new concurrency concerns in this patch.
  • Lifecycle/static initialization: Not applicable.
  • Configuration: No new config item, but behavior depends on existing enable_partition_analyze; the enabled path regresses.
  • Compatibility: No FE/BE protocol, storage-format, or rolling-upgrade compatibility change.
  • Parallel code paths: Applicable. There are two functional paths here: merged partition stats and table-level fallback. The fix must distinguish them; only the fallback path should be rescaled.
  • Special conditional checks: The new scale logic is not sufficient because it does not distinguish fallback stats from exact merged partition stats.
  • Test coverage: Insufficient. The added regression exercises the default enable_partition_analyze=false path only; it needs a case for enable_partition_analyze=true, preferably selecting multiple partitions so the exact merged numNulls is observable.
  • Observability: No additional observability appears necessary for this optimizer change.
  • Transaction/persistence: Not applicable.
  • Data writes/modifications: Not applicable.
  • FE-BE variable passing: Not applicable.
  • Performance: No meaningful performance concern found; the blocking issue is correctness.
  • Other issues: No additional blocking issues beyond the incorrect rescaling and missing coverage above.

colStatsBuilder.normalizeAvgSizeByte(slot.getDataType());
//scale null_num
double scale = tableRowCount == 0 ? 1 : selectedPartitionsRowCount / tableRowCount;
colStatsBuilder.setNumNulls(colStatsBuilder.getNumNulls() * scale);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When enable_partition_analyze is on and every selected partition has cached stats, getColumnStatistic(..., selectedPartitionNames) already returns the merged stats for exactly those partitions. Scaling numNulls again by selectedPartitionsRowCount / tableRowCount undercounts nulls by the prune ratio. For example, selecting two 4-row partitions that each contain one null produces a merged numNulls = 2, but this code changes it to 8 / 12 * 2 = 1.333.... That regresses scan stats for IS NULL filters and downstream selectivity that depends on null counts. The scaling needs to happen only on the table-level fallback path, not when merged partition stats are available.

def colStats = sql "show column stats ptable";
def memo = sql "explain memo plan select * from ptable where d='2017-01-01'"
// check numNulls=1.0000 for column val, which is scaled from 3 to 1 according to the partition pruning result.
assertTrue(memo.toString().contains("val#1 -> ndv=1.0000, min=2.000000(2), max=2.000000(2), count=4.0000, numNulls=1.0000"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This regression only covers the default enable_partition_analyze = false path, so it never exercises the merged partition-stats branch that this PR also changes. With enable_partition_analyze = true, the new unconditional scaling above turns an exact merged numNulls into a smaller value. Please add a case that enables partition analyze (and restores it in finally, like query_p0/stats/partition_col_stats.groovy) and verifies the selected-partition numNulls stays exact instead of being rescaled.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 1.02% (8/787) 🎉
Increment coverage report
Complete coverage report

@englefly

Copy link
Copy Markdown
Contributor Author

run nonConcurrent

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 0.22% (4/1838) 🎉
Increment coverage report
Complete coverage report

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Apr 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@englefly
englefly merged commit 336bc56 into apache:master Apr 22, 2026
32 of 33 checks passed
@englefly
englefly deleted the partition-null-num branch April 22, 2026 03:27
github-actions Bot pushed a commit that referenced this pull request Apr 22, 2026
…2265)

### What problem does this PR solve?
For an OlapTable, when only a subset of partitions is selected, the
num_nulls value in column statistics needs to be scaled proportionally.
github-actions Bot pushed a commit that referenced this pull request Apr 22, 2026
…2265)

### What problem does this PR solve?
For an OlapTable, when only a subset of partitions is selected, the
num_nulls value in column statistics needs to be scaled proportionally.
yiguolei pushed a commit that referenced this pull request Apr 23, 2026
…n pruned #62265 (#62694)

Cherry-picked from #62265

Co-authored-by: minghong <zhouminghong@selectdb.com>
yiguolei pushed a commit that referenced this pull request May 7, 2026
…n pruned #62265 (#62693)

Cherry-picked from #62265

Co-authored-by: minghong <zhouminghong@selectdb.com>
zhaorongsheng pushed a commit to zhaorongsheng/doris that referenced this pull request Jun 4, 2026
…ache#62265)

### What problem does this PR solve?
For an OlapTable, when only a subset of partitions is selected, the
num_nulls value in column statistics needs to be scaled proportionally.
morrySnow pushed a commit that referenced this pull request Jul 13, 2026
### What problem does this PR solve?

Related PR: #62265

Problem Summary:

`test_scale_num_nulls` checks that table-level `numNulls=3` is scaled to
`1` when partition pruning selects 4 of 12 rows. The regression case
executes `EXPLAIN MEMO PLAN` immediately after insert and analyze, but
Cloud P0 reports the physical partition row count asynchronously. The
planner can therefore observe a transient selected-partition row count
of zero, while waiting for the real row count can take up to two
minutes.

This change:

- adds deterministic FE unit coverage that invokes
`StatsCalculator.computeOlapScan()` with a three-partition OLAP scan;
- fixes the table row count at 12, selected-partition row count at 4,
and cached table-level column statistics at `ndv=1`, `min=max=2`, and
`numNulls=3`;
- verifies the final scan statistics have `ndv=1`, `min=max=2`,
`count=4`, and scaled `numNulls=1`;
- removes the timing-dependent Groovy regression case.

The unit test exercises the production partition-pruning statistics path
using fixed in-memory inputs. It has no cluster, physical row-count
reporting, polling, sleep, network, or storage dependency. Production
behavior is unchanged.
yiguolei pushed a commit that referenced this pull request Jul 16, 2026
…est (#65656)

### What problem does this PR solve?

Related PR: #65445

Problem Summary:

Backport #65445 to branch-4.1.

The regression case `test_scale_num_nulls` depends on asynchronously
visible physical row counts. When the physical row count is still 0,
Nereids scales the selected-partition column statistics to 0 even though
the injected partition/table statistics are correct, making the case
flaky.

Replace the environment-dependent Groovy regression case with a
deterministic FE unit test that directly constructs the partition/table
statistics and verifies selected-partition scaling, including row count,
NDV, min/max, count, and numNulls.

### Coverage rationale

- This is a branch backport of merged PR #65445. The same planner-level
coverage concern was raised in [the upstream review
thread](#65445 (comment)),
then explicitly resolved by a maintainer before the PR was approved and
merged.
- The independent behavior introduced with #62265 is selected-partition
statistics scaling. The replacement test invokes the real
`StatsCalculator.computeOlapScan()` path and verifies row count, NDV,
min/max, count, and `numNulls`. SQL predicate-to-partition selection
remains covered by `PruneOlapScanPartitionTest` on this release branch.
- The removed cluster case sampled the strict physical partition row
count immediately after insert/analyze. In Cloud P0 that value can
remain 0 for up to two minutes even when table-level column statistics
are correct. Retaining the case or waiting for that report would
preserve the flake or add up to two minutes to the suite.
- `SHOW COLUMN STATS` was only failure diagnostics, and memo text
formatting was not an independent assertion target of this case.

### Release note

None

### Check List (For Author)

- Test
    - [ ] Regression test
    - [x] Unit Test
    - [ ] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason

  Local validation:
-
`StatsCalculatorTest#testComputeOlapScanScalesNumNullsForSelectedPartitions`:
passed (1 test)
  - `StatsCalculatorTest`: passed (17 tests)
  - `mvn -pl fe-core -am checkstyle:check`: passed (0 violations)

- Behavior changed:
    - [x] No.
    - [ ] Yes.

- Does this need documentation?
    - [x] No.
    - [ ] Yes.

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.0.6-merged dev/4.1.1-merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants