Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/PlanViewer.Core/Services/PlanAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@

// Rule 2: Eager Index Spools — optimizer building temporary indexes on the fly
if (!cfg.IsRuleDisabled(2) && node.LogicalOp == "Eager Spool" &&
node.PhysicalOp.Contains("Spool", StringComparison.OrdinalIgnoreCase))
node.PhysicalOp.Contains("Index", StringComparison.OrdinalIgnoreCase))
{
var message = "SQL Server is building a temporary index in TempDB at runtime because no suitable permanent index exists. This is expensive — it builds the index from scratch on every execution. Create a permanent index on the underlying table to eliminate this operator entirely.";
if (!string.IsNullOrEmpty(node.SuggestedIndex))
Expand Down Expand Up @@ -949,7 +949,7 @@
// Rule 28: Row Count Spool — NOT IN with nullable column
// Pattern: Row Count Spool with high rewinds, child scan has IS NULL predicate,
// and statement text contains NOT IN
if (!cfg.IsRuleDisabled(28) && node.PhysicalOp.Contains("Row Count Spool"))

Check warning on line 952 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.

Check warning on line 952 in src/PlanViewer.Core/Services/PlanAnalyzer.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Dereference of a possibly null reference.
{
var rewinds = node.HasActualStats ? (double)node.ActualRewinds : node.EstimateRewinds;
if (rewinds > 10000 && HasNotInPattern(node, stmt))
Expand Down
11 changes: 11 additions & 0 deletions tests/PlanViewer.Core.Tests/PlanAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ public void Rule02_EagerIndexSpool_DetectedInLazySpoolPlan()
Assert.Contains(warnings, w => w.Message.Contains("temporary index in TempDB"));
}

[Fact]
public void Rule02_EagerIndexSpool_NotFiredForEagerTableSpool()
{
// Plan with Eager Table Spool (PhysicalOp="Table Spool", LogicalOp="Eager Spool")
// should NOT trigger the Eager Index Spool warning
var plan = PlanTestHelper.LoadAndAnalyze("eager_table_spool_plan.sqlplan");
var warnings = PlanTestHelper.WarningsOfType(plan, "Eager Index Spool");

Assert.Empty(warnings);
}

// ---------------------------------------------------------------
// Rule 3: Serial Plan
// ---------------------------------------------------------------
Expand Down
Loading
Loading