Repository navigation
Plan analysis: run the benefit scorer at every entry point and show each finding's benefit (#4546) - #4552
Merged
Conversation
erikdarlingdata
marked this pull request as ready for review
September 28, 2026 04:09
erikdarlingdata
added a commit
that referenced
this pull request
Sep 28, 2026
…e waits get a real benefit (#4555) Plan analysis turns a plan's wait statistics into findings, and gives external and preemptive waits a real benefit. Fixes #4516, fixes #4517, part of #4511. - BenefitScorer.ScoreWaitStats, matching PerformanceStudio, adds a "Wait: <type>" finding for each significant wait type in an actual plan, with a severity tier from its estimated benefit and a description from WaitStats.json. The file ships as an embedded resource of the shared plan-analysis assembly, so Darling, Lite and the viewer read the same copy. - External and preemptive waits get PerformanceStudio's separate benefit formula instead of being folded into operator time. - GetOperatorMaxThreadOwnCpuMs matches PerformanceStudio: it skips thread 0 and looks through batch mode zones and Compute Scalar pass-throughs. - The findings appear now that the scorer runs at every entry point (#4552). They reach only the plan warning fact and the advice headline's critical count, not any alert or health band. - Tests: PlanSync4516Tests, PlanSync4517Tests and PlanSync4517ProbeTests, failing without the change; two mutations fail them.
This was referenced Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4546
Part of #4511
Why
BenefitScorer.Scoreexisted but no product code called it: every entry point ran onlyPlanAnalyzer.Analyze. So no finding had a benefit value, and nothing the scorer computes was ever used.What changes
PlanAnalysisPipeline.Run(plan)(new, mirroring PerformanceStudio'sPlanAnalysisPipeline) runs the analyzer and then the scorer, and returns early for a plan with no statements (which is also what a plan the parser refuses looks like). It replaces the directPlanAnalyzer.Analyze(plan)call at all five entry points:PlanAdvisoryAggregator);PgDrillDownCollector.Plans);McpPlanAnalysisFormatter);Lite/Analysis/DrillDownCollector.Plans);PlanViewerControl.xaml.cs).max_benefit_percent(null when unscored), and findings are ordered by it, highest first, with unscored last. This is additive; the existing fields are unchanged.PlanWarningDisplay, so they can be tested outside the UI.Impact on stored advisories and alerts
This was checked before merge.
PLAN_WARNINGfact.FactScorerscores it presence-only (0.4), which is below the 0.75 Warning band and the 1.5 notification threshold.critical_countis read only by the advice headline text. Nothing readsMaxBenefitPercentoutside the scorer, the MCP output and the viewer.Test plan
BenefitScorerWiringTests:PlanAnalysisPipelinecallsPlanAnalyzer.Analyze(directly;McpPlanAnalysisFormatter, a Serial Plan finding carries a non-nullmax_benefit_percent. Runtime RED on dev:KeyNotFoundExceptiononmax_benefit_percent, since dev's JSON has no such key;Run_EmptyPlan_DoesNotThrow_AndLeavesPlanUnchanged).PlanViewerBenefitDisplayTests: the header with a benefit (⚠ Serial Plan — up to 67.5% benefit, plus[SQL Server]for engine warnings), the header without one, and the ordering 80, 20, null. These are compile-only RED on dev, becausePlanWarningDisplayis new.Scorecall fromPlanAnalysisPipeline.Runfails the MCP benefit fact.Total: 239, Failed: 0, Skipped: 2(the live-Postgres plan-tool class runs in CI).Lite.TestsandPerformanceMonitor.Uibuild.Also in this PR (test-only):
PgWaitSamplerLiveTests.OneCycleAgainstAStockTarget_…now readsquery_idand picks its own lock row (the one with the most samples) instead of asserting there is exactly one(Lock, relation)row. The sampler polls every session on the test server, so a concurrent test class's own relation-lock wait can add a second row; this PR's new test classes shifted the CI shard layout enough to expose it.CHANGELOG
SECTION: Fixed
ENTRY: - Plan analysis now scores each finding's benefit, and the plan viewer and MCP plan tools show it ([#4552]) - The benefit scorer was never run, so no finding had a benefit value. Findings are now ordered by their estimated benefit. The viewer's headers read "— up to X% benefit", and the MCP plan tools report
max_benefit_percent. This turns on the Serial Plan and Bare Scan benefit estimates.REF: [#4552]: #4552