Skip to content

statistics: fix targeted stats cache refresh after analyze#69883

Open
wlwilliamx wants to merge 2 commits into
pingcap:masterfrom
wlwilliamx:xwl/fix-targeted-stats-cache-update
Open

statistics: fix targeted stats cache refresh after analyze#69883
wlwilliamx wants to merge 2 commits into
pingcap:masterfrom
wlwilliamx:xwl/fix-targeted-stats-cache-update

Conversation

@wlwilliamx

@wlwilliamx wlwilliamx commented Jul 16, 2026

Copy link
Copy Markdown

What problem does this PR solve?

Issue Number: close #69882

Problem Summary:

ANALYZE TABLE synchronously refreshes analyzed statistics through a targeted stats cache update. That path reused the cache-wide version lower bound, so an unrelated stats update could move the watermark past the analyzed table's persisted version and leave its cached entry pseudo.

What changed and how does it work?

  • Query targeted stats updates by the requested table IDs without applying the cache-wide version lower bound. Full cache updates retain the existing version filter, and targeted updates still do not advance the cache-wide watermark.
  • Refresh only physical statistics IDs actually persisted by the analyze tasks. Refresh a partitioned table's logical ID only when global stats persistence wrote data.
  • Report partial global stats writes and preserve the first write error so callers can distinguish no write from a partial update.
  • Add regression coverage for a cache-wide watermark ahead of the requested table, static partition analyze, successful and failed dynamic global merges, and partial global stats writes.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Unit tests:

  • ./tools/check/failpoint-go-test.sh pkg/statistics/handle/handletest/statstest -run '^TestStatsCacheProcess$' -count=1
  • ./tools/check/failpoint-go-test.sh pkg/executor/test/analyzetest -run '^TestAnalyzeRefreshesOnlyPersistedStats$' -count=1
  • ./tools/check/failpoint-go-test.sh pkg/statistics/handle/globalstats -run '^TestWriteGlobalStatsToStoragePreservesFirstError$' -count=1

Manual checks:

  • make bazel_prepare
  • make check-bazel-prepare
  • make fmt
  • make lint
  • git diff --check

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

Fix an issue where `ANALYZE TABLE` could leave pseudo statistics in the cache after another table advanced the cache-wide stats version.

Summary by CodeRabbit

  • Bug Fixes

    • Improved partition ANALYZE to refresh global stats metadata based on what was actually persisted, and avoid incorrectly refreshing from non-updated sources.
    • Preserved the first global-stats persistence error while continuing other saves.
    • Enhanced targeted statistics cache updates to maintain cached histograms/pseudo state correctly.
  • Tests

    • Added a new test validating global stats refresh behavior when only persistence updates should occur and when global merge failures happen.
    • Added coverage for persistence failure handling during global stats writes, and adjusted stats-cache test expectations.
    • Updated test sharding counts.
  • Documentation

    • Refined statistics/analyze test guideline descriptions.

Targeted stats refreshes reused the cache-wide version lower bound. An
unrelated table could therefore move the watermark past the analyzed table
and leave pseudo stats in memory after ANALYZE.

Reload explicitly requested IDs without that lower bound and only refresh
physical or global IDs whose analyze results were persisted. Preserve the
first global stats write error while tracking partial writes.
@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Jul 16, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign terry1purcell for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. component/statistics sig/planner SIG: Planner labels Jul 16, 2026
@pingcap-cla-assistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c8f79ed-4a60-4587-9f0e-b99786a3ad7e

📥 Commits

Reviewing files that changed from the base of the PR and between 0842d79 and bf3197d.

📒 Files selected for processing (4)
  • pkg/executor/analyze.go
  • pkg/executor/test/analyzetest/analyze_test.go
  • pkg/statistics/handle/cache/statscache.go
  • pkg/statistics/handle/types/interfaces.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/executor/analyze.go
  • pkg/executor/test/analyzetest/analyze_test.go

📝 Walkthrough

Walkthrough

The change fixes targeted statistics refreshes by using physical statistics IDs, separating targeted and full cache queries, and tracking which global statistics writes persisted. New tests cover partial persistence failures, pseudo-stat replacement, version handling, and partition analyze behavior.

Changes

Statistics refresh correctness

Layer / File(s) Summary
Global statistics persistence outcomes
pkg/statistics/handle/types/interfaces.go, pkg/statistics/handle/globalstats/global_stats.go, pkg/statistics/handle/globalstats/global_stats_test.go, pkg/statistics/handle/globalstats/BUILD.bazel, .agents/skills/tidb-test-guidelines/references/statistics-case-map.md
Global statistics merge and storage now return write status, continue after individual save failures, preserve the first error, and test these outcomes.
Analyze refresh ID propagation
pkg/executor/analyze.go, pkg/executor/analyze_global_stats.go, pkg/executor/test/analyzetest/analyze_test.go, pkg/executor/test/analyzetest/BUILD.bazel, .agents/skills/tidb-test-guidelines/references/executor-case-map.md
Analyze execution refreshes physical statistics IDs, incorporates persisted global-statistics updates, and tests partition analyze behavior under successful and failed merges.
Targeted cache update semantics
pkg/statistics/handle/cache/statscache.go, pkg/statistics/handle/handletest/statstest/stats_test.go, .agents/skills/tidb-test-guidelines/references/statistics-case-map.md
Targeted cache updates select requested tables without applying the cache-wide version filter, preserve metadata-related cache state, and validate version and pseudo-stat behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: 0xpoe, terry1purcell, winoros

Poem

A rabbit hops through stats anew,
With cached leaves and versions true.
Failed writes whisper, “try the rest,”
Persisted numbers pass the test.
Pseudo clouds fade from view—
Hop, hop, refresh! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change to targeted stats cache refresh after ANALYZE.
Description check ✅ Passed The description follows the template well, includes the issue number, problem summary, changes, tests, and release note.
Linked Issues check ✅ Passed The code changes remove the cache-wide version filter for targeted updates and keep the watermark unchanged, matching #69882.
Out of Scope Changes check ✅ Passed The additional test and BUILD/doc map updates support the targeted stats refresh fix and do not appear unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="Running error: context loading failed: failed to load packages: failed to load packages: failed to load with go/packages: context deadline exceeded"
level=error msg="Timeout exceeded: try increasing it by passing --timeout option"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/executor/analyze_global_stats.go (1)

46-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Eliminate the redundant tableIDs map.

The tableIDs map is an exact copy of globalStatsTableIDs and can be safely removed to avoid unnecessary allocations. You can iterate over globalStatsTableIDs directly when dumping stats to historical storage later in the function.

♻️ Proposed refactor

Apply the following change here:

-	tableIDs := make(map[int64]struct{}, len(globalStatsTableIDs))
 	updatedTableIDs := make([]int64, 0, len(globalStatsTableIDs))
 	for tableID := range globalStatsTableIDs {
-		tableIDs[tableID] = struct{}{}
 		tableUpdated := false

And update the historical storage loop below (line 92):

	for tableID := range globalStatsTableIDs {
		// Dump stats to historical storage.
		if err := recordHistoricalStats(e.Ctx(), tableID); err != nil {
			logutil.BgLogger().Error("record historical stats failed", zap.Error(err))
		}
	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/executor/analyze_global_stats.go` around lines 46 - 50, Remove the
redundant tableIDs map from the analyzeGlobalStats flow, including its
population inside the loop. Update the historical stats dumping loop to iterate
directly over globalStatsTableIDs while preserving the existing
recordHistoricalStats and error-logging behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/executor/analyze_global_stats.go`:
- Around line 46-50: Remove the redundant tableIDs map from the
analyzeGlobalStats flow, including its population inside the loop. Update the
historical stats dumping loop to iterate directly over globalStatsTableIDs while
preserving the existing recordHistoricalStats and error-logging behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3fa63576-7f55-4c2a-8695-5b2e821540c8

📥 Commits

Reviewing files that changed from the base of the PR and between 531e40c and 0842d79.

📒 Files selected for processing (12)
  • .agents/skills/tidb-test-guidelines/references/executor-case-map.md
  • .agents/skills/tidb-test-guidelines/references/statistics-case-map.md
  • pkg/executor/analyze.go
  • pkg/executor/analyze_global_stats.go
  • pkg/executor/test/analyzetest/BUILD.bazel
  • pkg/executor/test/analyzetest/analyze_test.go
  • pkg/statistics/handle/cache/statscache.go
  • pkg/statistics/handle/globalstats/BUILD.bazel
  • pkg/statistics/handle/globalstats/global_stats.go
  • pkg/statistics/handle/globalstats/global_stats_test.go
  • pkg/statistics/handle/handletest/statstest/stats_test.go
  • pkg/statistics/handle/types/interfaces.go

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.89247% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.2762%. Comparing base (531e40c) to head (bf3197d).
⚠️ Report is 23 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #69883        +/-   ##
================================================
- Coverage   76.3207%   74.2762%   -2.0445%     
================================================
  Files          2041       2068        +27     
  Lines        559975     585444     +25469     
================================================
+ Hits         427377     434846      +7469     
- Misses       131697     149282     +17585     
- Partials        901       1316       +415     
Flag Coverage Δ
integration 42.2316% <69.8924%> (+2.5263%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 60.4471% <ø> (ø)
parser ∅ <ø> (∅)
br 47.4060% <ø> (-15.3154%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ti-chi-bot

ti-chi-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

@wlwilliamx: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-unit-test-next-gen bf3197d link true /test pull-unit-test-next-gen
idc-jenkins-ci-tidb/unit-test bf3197d link true /test unit-test

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/statistics release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

statistics: targeted stats refresh can leave pseudo stats after analyze

1 participant