Skip to content

Add 13 new plan analysis rules to PlanAnalyzer#327

Merged
erikdarlingdata merged 2 commits intodevfrom
feature/plan-analyzer-rules
Feb 26, 2026
Merged

Add 13 new plan analysis rules to PlanAnalyzer#327
erikdarlingdata merged 2 commits intodevfrom
feature/plan-analyzer-rules

Conversation

@erikdarlingdata
Copy link
Owner

Summary

  • Expands PlanAnalyzer from 11 to 24 rules with domain-specific detection for common SQL Server performance anti-patterns
  • New rules: non-SARGable predicates (5 sub-patterns), data type mismatch, lazy spool ratio, join OR clause, NL high executions, many-to-many merge, large memory grant with sort/hash guidance, compile memory exceeded, high compile CPU, local variables, CTE multi-reference, table variables, TVFs, top above scan
  • Fixes existing scan rules to exclude columnstore indexes (designed to be scanned)
  • Extracts IsRowstoreScan() helper for consistent rowstore scan detection

Test plan

  • Open a plan with implicit conversions — verify "Non-SARGable Predicate" warning fires
  • Open a plan with YEAR() or DATEPART() in WHERE — verify function call detection
  • Open a plan with table variables — verify "Table Variable" warning
  • Open a plan with a TVF — verify "Table-Valued Function" warning
  • Open a plan with a many-to-many merge join — verify warning fires
  • Open a columnstore scan plan — verify NO scan-with-predicate warning fires
  • Verify existing warnings still fire (filter, eager spool, UDF, spills, etc.)

🤖 Generated with Claude Code

erikdarlingdata and others added 2 commits February 26, 2026 16:02
Expands the plan analyzer from 11 to 24 rules with domain-specific
detection patterns for common SQL Server performance anti-patterns.

New rules:
- Non-SARGable predicates (CONVERT_IMPLICIT, function calls, ISNULL,
  leading wildcard LIKE, CASE expressions)
- Data type mismatch (GetRangeWithMismatchedTypes)
- Lazy spool ineffective rebind/rewind ratio
- Join OR clause expansion (Concatenation + Constant Scan)
- Nested Loops high inner-side execution count
- Many-to-many Merge Join
- Large memory grant with sort/hash consumer identification
- Compile memory exceeded (early abort)
- High compile CPU (>= 1000ms)
- Local variables without RECOMPILE
- CTE referenced multiple times
- Table variable detection
- Table-valued function detection
- Top above rowstore scan

Also fixes existing scan rules to exclude columnstore indexes
(designed to be scanned) and extracts IsRowstoreScan() helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ction reorder

- Add statement-level Rule 4 check for UDF execution timing from QueryTimeStats
  (some plans report UDF timing only at statement level, not per-node)
- Reorder non-SARGable detection: check CASE expression before CONVERT_IMPLICIT
  since CASE bodies often contain CONVERT_IMPLICIT that isn't the root cause

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@erikdarlingdata erikdarlingdata merged commit 0816ede into dev Feb 26, 2026
3 checks passed
@erikdarlingdata erikdarlingdata deleted the feature/plan-analyzer-rules branch February 26, 2026 23:48
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