Skip to content

sp_QuickieStore: add @find_parameter_sensitive mode - #845

Merged
erikdarlingdata merged 1 commit into
devfrom
sp_quickiestore/find-parameter-sensitive
Jul 29, 2026
Merged

sp_QuickieStore: add @find_parameter_sensitive mode#845
erikdarlingdata merged 1 commit into
devfrom
sp_quickiestore/find-parameter-sensitive

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Summary

New takeover mode that finds parameter sensitive queries by grouping Query Store runtime stats at the plan-shape grain (query_hash + query_plan_hash) and ranking shapes by how volatile their runtime metrics are.

  • Every plan_id that compiled to the same shape is analyzed together, so recompiles of the same plan aggregate into one row
  • Ranking is an execution-weighted coefficient of variation combined across runtime stat intervals from the (previously unused) stdev columns; @sort_order picks the ranked metric
  • Only regular executions feed the statistics; aborted and exception executions are counted and surfaced separately
  • Signals column annotates what the swings mean: parameter sensitive (cpu swings, rows flat), row driven, intermittent waits, memory grant swings, tempdb swings, timeouts, PSP variants involved (2022+), and other-plan-shapes divergence for the plan-flip flavor
  • Summary result set first (shapes analyzed / past floors / surfaced / multi-shape hashes), then one row per shape with min/avg/max/volatility for cpu, duration, rows, plan XML, top waits (2017+), and a variance_metrics XML rollup
  • Noise floors: minimum executions (reuses @execution_count) and minimum work (max cpu >= 10ms or max duration >= 100ms; @duration_ms takes over when set)
  • Version-gated like the rest of the proc: tempdb metrics 2017+, wait stats 2017+, query variants 2022+

Also: primary keys on both modes' staging temp tables, and deterministic object-name resolution in both @find_high_impact and the new mode.

Test plan

  • Full assertion matrix on SQL Server 2022: 157/157 (23 new assertions, including a skewed-workload fixture where the parameter sensitive signal must fire, conflict guard errors, floors, and the debug path against an empty Query Store)
  • Clean installs and version-gated runs on 2016, 2017, 2019, 2022, 2025
  • Real-data validation: StackOverflow2010 (2019), StackOverflow2013 + StackOverflow2010 + DBA (2022), StackOverflow2013 (2025), including a historical-window run proving window-scoped last_execution_time
  • Reviewed by style and correctness passes; all findings fixed and re-verified

🤖 Generated with Claude Code

Finds plan shapes (query_hash + query_plan_hash) whose runtime metrics
swing wildly across executions of the same plan. Ranks shapes by an
execution-weighted coefficient of variation built from the previously
unused stdev columns, feeds statistics from regular executions only
(aborted/exception counted separately), and annotates signals:
parameter sensitive, row driven, intermittent waits, memory and tempdb
swings, timeouts, PSP variants, and cross-shape divergence. Takeover
mode like @find_high_impact: summary result set, one row per shape,
plan XML, top waits on 2017+, variant flags on 2022+.

Also adds primary keys to both modes' staging temp tables and makes
object-name resolution deterministic in both.

Tested: 157-assertion matrix on SQL Server 2022 (23 new assertions,
including a skewed-workload fixture where the parameter sensitive
signal must fire); clean installs and version-gated runs on
2016/2017/2019/2022/2025; real-data validation against StackOverflow
databases on 2019, 2022, and 2025.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@erikdarlingdata
erikdarlingdata merged commit ae15c41 into dev Jul 29, 2026
6 checks passed
@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Claude finished @erikdarlingdata's task in 3m 16s —— View job


Reviewing PR #845: sp_QuickieStore: add @find_parameter_sensitive mode

  • Gather context (diff, changed files, CLAUDE.md style guide)
  • Review sp_QuickieStore.sql changes for correctness, version compatibility, self-containment, style
  • Review test/README changes
  • Post final review feedback

Summary

This is a large (~2,300 line) but well-contained addition of a new takeover mode. I reviewed the full diff against origin/main and spot-checked the new mode's conventions against the rest of the ~16k-line procedure. Nothing blocking found.

Correctness

  • The execution-weighted variance combination (SUM(n * (stdev² + avg²)) / SUM(n) − combined_avg², floored at 0 before SQRT) is the standard parallel-variance formula, computed in float to avoid decimal overflow on squared microsecond values — the accompanying comment explains why, which is appreciated given how easy this is to get subtly wrong.
  • Only execution_type = 0 (regular) executions feed the stats, with aborted/exception executions counted separately — correctly avoids poisoning min/max/stdev with truncated abort metrics.
  • All ratio divisions (cpu_ratio, duration_ratio, rows_ratio, memory_ratio, tempdb_ratio) clamp the denominator (0.001 ms / 1 row) instead of relying on NULLIF, so a zero-valued min can't produce a divide-by-zero or an undefined ratio — verified this is deliberate per the inline comment.
  • The memory/reads/writes/tempdb * 8.0 / 1024.0 page→MB conversion matches the existing @find_high_impact mode's conversion exactly (sp_QuickieStore.sql:4974-4997), so it's consistent with established convention rather than a newly-invented factor.
  • The query_sql_text control-character scrubbing (nested REPLACE/NCHAR chain + FOR XML PATH trick) is the same pattern already used elsewhere in the procedure (sp_QuickieStore.sql:10496), not a new one-off.
  • The three new mutual-exclusion guards (@find_high_impact, @get_all_databases, @log_to_table) RAISERROR and RETURN before any temp tables are touched, matching the existing takeover-mode guard pattern.

Version gating

  • Reuses the procedure's existing gating variables directly: @new for 2017+ (tempdb metrics, wait stats), @sql_2022_views for 2022+ (query variants/PSP), @query_store_waits_enabled for wait stats availability — no new ad hoc version checks introduced, no new-syntax (STRING_AGG, GREATEST/LEAST, etc.) usage.
  • Pre-2017 tempdb columns are populated with CONVERT(float, NULL) rather than 0, with a comment explaining that 0 would misrepresent "no tempdb use" as a real measurement — this correctly makes the attribute drop out of the variance_metrics XML rollup entirely on older versions.

Self-containment

  • No new procedures, functions, or views — everything lives in the one staging-temp-table pipeline inside the procedure, consistent with the project's no-dependency constraint.

Style

  • Confirmed no tabs, block comments only, consistent trailing commas, COUNT_BIG/CONVERT-over-CAST used throughout the new code — matches CLAUDE.md.
  • The added PRIMARY KEY CLUSTERED on the two @find_high_impact staging tables and the new ORDER BY so.object_id before OBJECT_SCHEMA_NAME/OBJECT_NAME calls are good determinism fixes, as called out in the PR description.

Minor, non-blocking observation

  • The noise-floor predicate (total_executions >= @ps_min_executions and the cpu/duration work floor) is written out twice — once in the #ps_interesting insert, once in the summary counts query. Both copies are identical today, but a future edit to one without the other would silently desync shapes_past_floors from what's actually surfaced. Not asking for a change here since the project avoids introducing helper objects for this kind of thing, just flagging it for awareness.

Test plan in the PR description (157/157 assertions, multi-version clean installs, real-data validation against StackOverflow/DBA databases) is thorough for a change of this size.

@erikdarlingdata
erikdarlingdata deleted the sp_quickiestore/find-parameter-sensitive branch July 29, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant