Skip to content

planner, statistics: rewrite dynamic partition analyze for legacy stats version#67178

Merged
ti-chi-bot[bot] merged 6 commits intopingcap:masterfrom
0xPoe:poe-patch-global-stats
Mar 26, 2026
Merged

planner, statistics: rewrite dynamic partition analyze for legacy stats version#67178
ti-chi-bot[bot] merged 6 commits intopingcap:masterfrom
0xPoe:poe-patch-global-stats

Conversation

@0xPoe
Copy link
Copy Markdown
Member

@0xPoe 0xPoe commented Mar 20, 2026

What problem does this PR solve?

Issue Number: ref #63579

Problem Summary:

Dynamic partition analyze could rebuild global stats with the session-selected analyze version while some persisted table or partition stats were still on legacy version 1.

What changed and how does it work?

When dynamic ANALYZE TABLE ... PARTITION ... sees a stats-version mismatch, it now expands to all partitions before the global-stats merge. This PR also adds manual-analyze and auto-analyze regressions for the rewrite path and removes the related stale FIXMEs.

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.

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.

None

Summary by CodeRabbit

  • Bug Fixes

    • Detects and rewrites legacy statistics versions correctly for partitioned tables and shows a warning when a rewrite occurs.
  • Refactor

    • Streamlined analyze-version resolution to consistently validate global and per-partition statistics.
  • Tests

    • Expanded tests to cover partitioned tables, assert rewrite behavior and warnings, and verify persisted stats versions update.

@ti-chi-bot ti-chi-bot bot added the release-note-none Denotes a PR that doesn't merit a release note. label Mar 20, 2026
@pantheon-ai
Copy link
Copy Markdown

pantheon-ai bot commented Mar 20, 2026

Review Complete

Findings: 2 issues
Posted: 1
Duplicates/Skipped: 1

ℹ️ Learn more details on Pantheon AI.

@ti-chi-bot ti-chi-bot bot added component/statistics sig/planner SIG: Planner size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Mar 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors analyze-version resolution to remove the physicalIDs parameter and instead validate the requested analyze version against the table's global stats and, for partitioned tables, every partition. Planner call sites updated to use the new API and to warn/reanalyze all partitions when legacy stats are detected; tests extended to verify v1→v2 rewrite behavior.

Changes

Cohort / File(s) Summary
Tests: analyze-version rewrite
pkg/executor/test/analyzetest/analyze_test.go, pkg/statistics/handle/autoanalyze/exec/exec_test.go
Extended tests to force legacy stats_ver = 1, reload in-memory stats, assert statistics.Version1, run analyze/auto-analyze, verify legacy-rewrite warning presence and that mysql.stats_histograms rows are rewritten to stats_ver = 2 for parent and partition table IDs.
Stats analyze API & implementation
pkg/statistics/handle/types/interfaces.go, pkg/statistics/handle/autoanalyze/autoanalyze.go
Removed physicalIDs parameter from ResolveAnalyzeVersion; implementation now checks global table stats first and then every partition for partitioned tables, returning early on mismatch.
Planner: analyze build paths
pkg/planner/core/planbuilder.go
Updated analyze builders to call ResolveAnalyzeVersion without physicalIDs; added special-case in full-sampling builder for dynamic partition pruning to recompute partition IDs/partition names and append a session warning when incompatible legacy stats require rewriting across partitions.
Tests: analyze job assertions & deps
pkg/planner/core/tests/analyze/analyze_test.go, pkg/planner/core/tests/analyze/BUILD.bazel
Replaced mysql.analyze_jobs row-count assertion with explicit stats handle reload, partition lookup, and per-partition IsAnalyzed()/non-pseudo checks; added pkg/parser/ast to test deps.
Comment cleanup
pkg/statistics/handle/globalstats/global_stats.go, pkg/statistics/handle/globalstats/global_stats_async.go
Removed outdated TODO/FIXME comment blocks related to analyze-version mismatch risk; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Planner as Planner
  participant StatsAnalyze as StatsAnalyze
  participant StatsHandle as StatsHandle
  participant MySQL as MySQL

  Client->>Planner: RUN ANALYZE TABLE ... (with requestedVersion)
  Planner->>StatsAnalyze: ResolveAnalyzeVersion(tblInfo, requestedVersion)
  StatsAnalyze->>MySQL: Read global stats for tblInfo.ID
  alt partitioned table
    StatsAnalyze->>MySQL: Read stats for each partition.ID
  end
  StatsAnalyze-->>Planner: (resolvedVersion, versionMatches)
  alt versionMatches == false and dynamic partition pruning
    Planner->>Planner: recompute physicalIDs/partitionNames (all partitions)
    Planner-->>Client: append session warning about rewrite & analyzing all partitions
  end
  Planner->>StatsHandle: perform analyze tasks (scan, collect, persist)
  StatsHandle->>MySQL: Update `mysql.stats_histograms` (set `stats_ver = 2`)
  MySQL-->>Client: Warnings (include legacy-rewrite message)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • henrybw
  • yudongusa
  • guo-shaoge
  • terry1purcell

Poem

🐰 I hopped through tables, partitions, and rows,
Checked versions where legacy trouble grows.
I nudged v1 to sparkle as v2,
Warned, re-analyzed each partition too—
Thump-thump, tidy stats and bright repose! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: rewriting dynamic partition analyze when legacy stats versions are present.
Description check ✅ Passed The description includes the required issue reference (ref #63579), a clear problem summary, explanation of changes, and completed test checklist with unit tests marked.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/statistics/handle/autoanalyze/exec/exec_test.go (1)

127-143: Decouple this warning assertion from earlier log history.

recorded still contains the warning from the non-partitioned half of the test, so require.Len(t, warnLogs, 2) and warnLogs[1] make this branch depend on earlier observer state. Snapshot the baseline before this AutoAnalyze call, or reset the observer, and assert only the new entry.

♻️ Suggested change
+	beforeWarns := len(recorded.FilterMessage("auto analyze rewrites legacy statistics version 1 to version 2").All())
 	require.NotPanics(t, func() {
 		ok := exec.AutoAnalyze(
 			sctx,
 			handle,
 			dom.SysProcTracker(),
 			statistics.Version2,
 			true,
 			"analyze table %n partition %n",
 			"pt",
 			"p0",
 		)
 		require.True(t, ok)
 	})
 
 	warnLogs = recorded.FilterMessage("auto analyze rewrites legacy statistics version 1 to version 2").All()
-	require.Len(t, warnLogs, 2)
-	require.Equal(t, "analyze table `pt` partition `p0`", warnLogs[1].ContextMap()["sql"])
+	require.Len(t, warnLogs, beforeWarns+1)
+	require.Equal(t, "analyze table `pt` partition `p0`", warnLogs[beforeWarns].ContextMap()["sql"])

Based on learnings: Applies to **/*_test.go : Keep test changes minimal and deterministic; avoid broad golden/testdata churn unless required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/statistics/handle/autoanalyze/exec/exec_test.go` around lines 127 - 143,
The test is brittle because recorded already contains an earlier warning, so
adjust the assertion around exec.AutoAnalyze to only inspect logs produced by
that call: before calling exec.AutoAnalyze(sctx, handle, dom.SysProcTracker(),
statistics.Version2, true, "analyze table %n partition %n", "pt", "p0"), capture
a baseline (e.g., len(recorded.All()) or call recorded.Clear()/reset the
observer) and then after the call filter the new messages and assert a single
new warning with ContextMap()["sql"] == "analyze table `pt` partition `p0` —
i.e., reference the existing recorded variable and the AutoAnalyze invocation to
isolate and assert only the new log entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/statistics/handle/autoanalyze/exec/exec_test.go`:
- Around line 127-143: The test is brittle because recorded already contains an
earlier warning, so adjust the assertion around exec.AutoAnalyze to only inspect
logs produced by that call: before calling exec.AutoAnalyze(sctx, handle,
dom.SysProcTracker(), statistics.Version2, true, "analyze table %n partition
%n", "pt", "p0"), capture a baseline (e.g., len(recorded.All()) or call
recorded.Clear()/reset the observer) and then after the call filter the new
messages and assert a single new warning with ContextMap()["sql"] == "analyze
table `pt` partition `p0` — i.e., reference the existing recorded variable and
the AutoAnalyze invocation to isolate and assert only the new log entry.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 719b5d89-c457-4df0-9acb-46fc4fb6339d

📥 Commits

Reviewing files that changed from the base of the PR and between 0a7bdc9 and afe47e6.

📒 Files selected for processing (6)
  • pkg/executor/test/analyzetest/analyze_test.go
  • pkg/planner/core/BUILD.bazel
  • pkg/planner/core/planbuilder.go
  • pkg/statistics/handle/autoanalyze/exec/exec_test.go
  • pkg/statistics/handle/globalstats/global_stats.go
  • pkg/statistics/handle/globalstats/global_stats_async.go
💤 Files with no reviewable changes (2)
  • pkg/statistics/handle/globalstats/global_stats_async.go
  • pkg/statistics/handle/globalstats/global_stats.go

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.5338%. Comparing base (34555ee) to head (fe27c0e).
⚠️ Report is 12 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #67178        +/-   ##
================================================
+ Coverage   77.8013%   78.5338%   +0.7325%     
================================================
  Files          2022       1952        -70     
  Lines        555411     547443      -7968     
================================================
- Hits         432117     429928      -2189     
+ Misses       121550     117052      -4498     
+ Partials       1744        463      -1281     
Flag Coverage Δ
integration 44.1298% <36.3636%> (-4.0004%) ⬇️
unit 76.9035% <75.0000%> (+0.5637%) ⬆️

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

Components Coverage Δ
dumpling 61.5065% <ø> (ø)
parser ∅ <ø> (∅)
br 48.9099% <ø> (-11.9340%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/planner/core/planbuilder.go (1)

2966-2969: Optional: deduplicate analyze-version mismatch handling in index paths.

buildAnalyzeIndex and buildAnalyzeAllIndex now have the same resolve+warning block. Consider extracting a small helper to keep warning semantics in one place and reduce drift risk.

Also applies to: 2980-2983

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/planner/core/planbuilder.go` around lines 2966 - 2969, Extract the
repeated resolve+warning logic into a small helper (e.g.,
handleAnalyzeVersionMismatch or ensureAnalyzeVersionConsistency) that calls
statsHandle.ResolveAnalyzeVersion(tblInfo, version) and, when versionIsSame is
false, appends the same warning via
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errors.NewNoStackError(...)); then
replace the duplicated blocks in buildAnalyzeIndex and buildAnalyzeAllIndex with
a call to that helper so the ResolveAnalyzeVersion call and the exact warning
message are managed in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/planner/core/planbuilder.go`:
- Around line 2966-2969: Extract the repeated resolve+warning logic into a small
helper (e.g., handleAnalyzeVersionMismatch or ensureAnalyzeVersionConsistency)
that calls statsHandle.ResolveAnalyzeVersion(tblInfo, version) and, when
versionIsSame is false, appends the same warning via
b.ctx.GetSessionVars().StmtCtx.AppendWarning(errors.NewNoStackError(...)); then
replace the duplicated blocks in buildAnalyzeIndex and buildAnalyzeAllIndex with
a call to that helper so the ResolveAnalyzeVersion call and the exact warning
message are managed in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 81feb920-5432-46c8-ad21-45840fb2da0f

📥 Commits

Reviewing files that changed from the base of the PR and between afe47e6 and fcc81ca.

📒 Files selected for processing (3)
  • pkg/planner/core/planbuilder.go
  • pkg/statistics/handle/autoanalyze/autoanalyze.go
  • pkg/statistics/handle/types/interfaces.go

Copy link
Copy Markdown
Member Author

@0xPoe 0xPoe left a comment

Choose a reason for hiding this comment

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

🔢 Self-check (PR reviewed by myself and ready for feedback)

  • Code compiles successfully

  • Unit tests added

  • No AI-generated elegant nonsense in PR.

  • Bazel files updated

  • Comments added where necessary

  • PR title and description updated

  • Documentation PR created (or confirmed not needed)

  • PR size is reasonable

/cc @mjonss @henrybw

@ti-chi-bot ti-chi-bot bot requested review from henrybw and mjonss March 20, 2026 09:40

tk.MustExec("analyze table t partition p0")
tk.MustQuery("show warnings").CheckContain(
"The analyze version from the session is not compatible with the existing statistics of the table. TiDB will analyze all partitions to rewrite the table statistics with the session-selected version",
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.

Is this something that would happen before this change? I mean that a single partition ANALYZE is expanded to full table ANALYZE and only given a warning afterwards?
Also is this documented?
What happens if you would do a single partition ANALYZE on a non-analyzed table?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Is this something that would happen before this change? I mean that a single partition ANALYZE is expanded to full table ANALYZE and only given a warning afterwards?

No, because we didn't handle this case at all. We just blindly merged them together, I believe.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Also is this documented?

This will be documented in my docs PR after I finish the entire removal project.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What happens if you would do a single partition ANALYZE on a non-analyzed table?

Check https://docs.pingcap.com/tidb/stable/system-variables/#tidb_skip_missing_partition_stats-new-in-v730

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.

OK, maybe we should follow tidb_skip_missing_partition_stats also when the tidb_analyze_version is not matching between partitions? I.e. if we are currently using v2, simply skip the partitions with v1 data if tidb_skip_missing_partition_stats is ON, otherwise simply fail with a descriptive error message?

If you consider this to be too much, I'm OK with simply document the behavior, since v1 is going away :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

OK, maybe we should follow tidb_skip_missing_partition_stats also when the tidb_analyze_version is not matching between partitions? I.e. if we are currently using v2, simply skip the partitions with v1 data if tidb_skip_missing_partition_stats is ON, otherwise simply fail with a descriptive error message?

This doesn't seem suitable for tidb_skip_missing_partition_stats. This setting controls the behavior when statistics are missing. However, in our case, the statistics exist but are mismatched. I believe a better approach is to clean up explicitly rather than quietly ignoring the issue until we happen to analyze this particular partition next time. I guess when users check the parition stats, they may also be confused because the stats exist, but they never get merged.

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.

OK, when documenting this, please consider adding a note about the possible workaround to remove the v1 stats first, to avoid a full table re-analyze during upgrade when only issuing single partition analyze.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/planner/core/tests/analyze/analyze_test.go (1)

76-84: Consider guarding partition-definition indexing for test resilience.

pi.Definitions[0] / [2] is correct for current DDL, but a small guard makes failures clearer if someone edits partition layout later.

♻️ Suggested small hardening
  pi := tbl.Meta().GetPartitionInfo()
  require.NotNil(t, pi)
+ require.GreaterOrEqual(t, len(pi.Definitions), 3)

  p0Stats := h.GetPhysicalTableStats(pi.Definitions[0].ID, tbl.Meta())
  require.False(t, p0Stats.Pseudo)
  require.True(t, p0Stats.IsAnalyzed())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/planner/core/tests/analyze/analyze_test.go` around lines 76 - 84, The
test directly indexes pi.Definitions[0] and [2]; add a guard asserting
pi.Definitions has at least 3 entries before those accesses (e.g. using
require.GreaterOrEqual/require.Len) so the failure is explicit if partition
layout changes; then proceed to call h.GetPhysicalTableStats with
pi.Definitions[0].ID and pi.Definitions[2].ID and keep the existing assertions
on p0Stats and p2Stats.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/planner/core/tests/analyze/analyze_test.go`:
- Around line 76-84: The test directly indexes pi.Definitions[0] and [2]; add a
guard asserting pi.Definitions has at least 3 entries before those accesses
(e.g. using require.GreaterOrEqual/require.Len) so the failure is explicit if
partition layout changes; then proceed to call h.GetPhysicalTableStats with
pi.Definitions[0].ID and pi.Definitions[2].ID and keep the existing assertions
on p0Stats and p2Stats.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8708b1ed-48f8-45db-9e4b-01c70a5ed5ef

📥 Commits

Reviewing files that changed from the base of the PR and between cf5c261 and 216902b.

📒 Files selected for processing (1)
  • pkg/planner/core/tests/analyze/analyze_test.go

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 20, 2026

/retest

Copy link
Copy Markdown
Contributor

@henrybw henrybw left a comment

Choose a reason for hiding this comment

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

This pretty much looks good to me, modulo a question about handling pseudo stats.

Comment on lines +300 to +301
globalStats := sa.statsHandle.GetPhysicalTableStats(tblInfo.ID, tblInfo)
if _, versionMatches := statistics.ResolveAnalyzeVersionOnTable(globalStats, requestedVersion); !versionMatches {
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.

Is globalStats for the given table guaranteed to never be pseudo stats?

I suppose I'm not sure what the right thing to do would be if they were: should pseudo stats always be considered a version mismatch? (Please correct me if I'm misunderstanding how pseudo stats work, though.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Is globalStats for the given table guaranteed to never be pseudo stats?

No, it's not 100%, but in most cases, it would be non-pseudo. We will have a background worker that loads the basic modify_count and count into memory. In reality, in most cases, it would be non-pseudo. The same rule applies to partition statistics as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I suppose I'm not sure what the right thing to do would be if they were: should pseudo stats always be considered a version mismatch? (Please correct me if I'm misunderstanding how pseudo stats work, though.)

I believe that in most cases, it is acceptable since the initial stats will load all metadata after the TiDB instance has started. So normally, it would be non-pseudo.

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 23, 2026

/retest

@0xPoe 0xPoe requested review from henrybw and mjonss March 23, 2026 08:12
Copy link
Copy Markdown
Contributor

@henrybw henrybw left a comment

Choose a reason for hiding this comment

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

Sounds good. LGTM!

@ti-chi-bot ti-chi-bot bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Mar 23, 2026
@0xTars
Copy link
Copy Markdown

0xTars commented Mar 23, 2026

I was able to reproduce a blocker on the PR head with a minimal static-prune test.

Repro outline:

  1. Create a partitioned table t(a, b, c) in static prune mode.
  2. Run ANALYZE TABLE t PARTITION p0 COLUMNS b.
  3. Run ANALYZE TABLE t PARTITION p1.
  4. Downgrade p1 to stats version 1 in mysql.stats_histograms, then refresh the stats cache.
  5. Re-run ANALYZE TABLE t PARTITION p0 COLUMNS b.

Expected: p0 should still only have histogram rows for the handle column a and the requested column b.

Actual on this branch: p0 gets an extra histogram row for column c, i.e. the partition-scoped analyze widens because another partition is still on v1.

Minimal regression test used locally
func TestAnalyzePartitionStaticVersionMismatchDoesNotExpandColumnScope(t *testing.T) {
	store, dom := testkit.CreateMockStoreAndDomain(t)
	tk := testkit.NewTestKit(t, store)
	testkit.WithPruneMode(tk, variable.Static, func() {
		tk.MustExec("use test")
		tk.MustExec("set @@session.tidb_analyze_version = 2")
		tk.MustExec(`create table t (a int, b int, c int, primary key(a))
partition by range (a) (
	partition p0 values less than (10),
	partition p1 values less than (20)
)`)
		tk.MustExec("insert into t values (1, 1, 1), (2, 2, 2), (11, 11, 11), (12, 12, 12)")

		tbl, err := dom.InfoSchema().TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t"))
		require.NoError(t, err)
		tblInfo := tbl.Meta()
		pi := tblInfo.GetPartitionInfo()
		require.NotNil(t, pi)
		h := dom.StatsHandle()

		tk.MustExec("analyze table t partition p0 columns b")
		tk.MustExec("analyze table t partition p1")
		tk.MustExec("update mysql.stats_histograms set stats_ver = 1 where table_id = ?", pi.Definitions[1].ID)
		h.Clear()
		require.NoError(t, h.Update(context.Background(), dom.InfoSchema(), pi.Definitions[0].ID, pi.Definitions[1].ID))

		p0HistSQL := fmt.Sprintf(
			"select hist_id, stats_ver from mysql.stats_histograms where table_id = %d and is_index = 0 order by hist_id",
			pi.Definitions[0].ID,
		)
		tk.MustQuery(p0HistSQL).Check(testkit.Rows(
			fmt.Sprintf("%d 2", tblInfo.Columns[0].ID),
			fmt.Sprintf("%d 2", tblInfo.Columns[1].ID),
		))

		tk.MustExec("analyze table t partition p0 columns b")

		tk.MustQuery(p0HistSQL).Check(testkit.Rows(
			fmt.Sprintf("%d 2", tblInfo.Columns[0].ID),
			fmt.Sprintf("%d 2", tblInfo.Columns[1].ID),
		))
	})
}

I verified it locally with:

go test --tags=intest ./pkg/executor/test/analyzetest -run TestAnalyzePartitionStaticVersionMismatchDoesNotExpandColumnScope -count=1

and it fails on this branch with:

expected:
[1 2]
[2 2]

actual:
[1 2]
[2 2]
[3 2]

The root cause looks like the new ResolveAnalyzeVersion() result is still feeding mustAllColumns := !versionMatches in static prune mode, even though the table-wide check is only needed for the dynamic-prune/global-stats rewrite path.

I think the fix should split the checks:

  • use a scoped version check over the requested physicalIDs for mustAllColumns / overwrite warnings
  • keep the global check (all partitions + global stats) only for the dynamic-prune partition-expansion path

A regression test along the lines of TestAnalyzePartitionStaticVersionMismatchDoesNotExpandColumnScope in pkg/executor/test/analyzetest/analyze_test.go should catch this.

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 23, 2026

/hold

For #67178 (comment)

@ti-chi-bot ti-chi-bot bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 23, 2026
@0xPoe 0xPoe force-pushed the poe-patch-global-stats branch 2 times, most recently from 6e4473a to 6b1a264 Compare March 24, 2026 08:25
@tiprow
Copy link
Copy Markdown

tiprow bot commented Mar 25, 2026

@lybcodes: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test fast_test_tiprow
/test tidb_parser_test

Use /test all to run all jobs.

Details

In response to this:

/test check-dev

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.

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 25, 2026

/retest

2 similar comments
@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 25, 2026

/retest

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 25, 2026

/retest

…ts version

planner: remove redundant tableStatsGetter helper interface

fix: update bazel

Signed-off-by: 0xPoe <techregister@pm.me>

fix: better API design

Signed-off-by: 0xPoe <techregister@pm.me>

fix: better comment

Signed-off-by: 0xPoe <techregister@pm.me>

fix: add sapce

Signed-off-by: 0xPoe <techregister@pm.me>

fix: add more checks

Signed-off-by: 0xPoe <techregister@pm.me>

fix: better code

Signed-off-by: 0xPoe <techregister@pm.me>

fix: update bazel

Signed-off-by: 0xPoe <techregister@pm.me>

fix: better code

Signed-off-by: 0xPoe <techregister@pm.me>

fix: update broken tests

Signed-off-by: 0xPoe <techregister@pm.me>

fix: update bazel

Signed-off-by: 0xPoe <techregister@pm.me>

fix: update broken tests

Signed-off-by: 0xPoe <techregister@pm.me>

fix: static mode mismatch

Signed-off-by: 0xPoe <techregister@pm.me>

chore: update bazel file

fix: better code

Signed-off-by: 0xPoe <techregister@pm.me>

fix

Signed-off-by: 0xPoe <techregister@pm.me>

fix

Signed-off-by: 0xPoe <techregister@pm.me>

fix: add more comments

Signed-off-by: 0xPoe <techregister@pm.me>
@0xPoe 0xPoe force-pushed the poe-patch-global-stats branch from ccba023 to 4edecda Compare March 25, 2026 18:00
Copy link
Copy Markdown
Contributor

@mjonss mjonss left a comment

Choose a reason for hiding this comment

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

LGTM, with some minor change requests.

@ti-chi-bot ti-chi-bot bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Mar 25, 2026
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Mar 25, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-03-23 18:52:39.654162777 +0000 UTC m=+207955.690233037: ☑️ agreed by henrybw.
  • 2026-03-25 23:36:25.417900385 +0000 UTC m=+397781.453970645: ☑️ agreed by mjonss.

@mjonss
Copy link
Copy Markdown
Contributor

mjonss commented Mar 25, 2026

/hold

Please feel free to unhold, when addressed my review comments.

@ti-chi-bot ti-chi-bot bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 25, 2026
0xPoe added 2 commits March 26, 2026 08:48
Signed-off-by: 0xPoe <techregister@pm.me>
Signed-off-by: 0xPoe <techregister@pm.me>
@ti-chi-bot ti-chi-bot bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Mar 26, 2026
0xPoe added 3 commits March 26, 2026 09:53
Signed-off-by: 0xPoe <techregister@pm.me>
Relax the assertion to match the stable partial-stats prefix instead of
depending on specific eviction detail strings.

Signed-off-by: 0xPoe <techregister@pm.me>
Signed-off-by: 0xPoe <techregister@pm.me>
Copy link
Copy Markdown
Contributor

@mjonss mjonss left a comment

Choose a reason for hiding this comment

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

LGTM, and thank you for also reflecting the changes in the new function names!

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Mar 26, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: henrybw, mjonss

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

The pull request process is described 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

@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 26, 2026

/unhold

@ti-chi-bot ti-chi-bot bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 26, 2026
@0xPoe
Copy link
Copy Markdown
Member Author

0xPoe commented Mar 26, 2026

/retest

@ti-chi-bot ti-chi-bot bot merged commit 5e3fbd8 into pingcap:master Mar 26, 2026
36 checks passed
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot bot commented Mar 26, 2026

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

Test name Commit Details Required Rerun command
idc-jenkins-ci-tidb/mysql-test fe27c0e link unknown /test mysql-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

approved component/statistics lgtm ok-to-test Indicates a PR is ready to be tested. release-note-none Denotes a PR that doesn't merit a release note. 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.

6 participants