From 19a008b4abfd9d0f1ab1684006220070842072da Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Mon, 6 Apr 2026 23:43:16 -0400 Subject: [PATCH] Gate XML MemoryGrantWarning at 1 GB to match Rule 9 threshold The plan XML's MemoryGrantWarning element fires for any grant size, including trivially small ones (1 MB). Gate at 1 GB to suppress noise, consistent with the analyzer's Rule 9 threshold. All values confirmed as KB across all example plans. Updated test to verify small grants are suppressed. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/PlanViewer.Core/Services/ShowPlanParser.cs | 18 ++++++++++++------ .../PlanViewer.Core.Tests/PlanAnalyzerTests.cs | 9 +++++---- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/PlanViewer.Core/Services/ShowPlanParser.cs b/src/PlanViewer.Core/Services/ShowPlanParser.cs index 5cf9f11..62ebf42 100644 --- a/src/PlanViewer.Core/Services/ShowPlanParser.cs +++ b/src/PlanViewer.Core/Services/ShowPlanParser.cs @@ -1665,7 +1665,8 @@ private static List ParseWarningsFromElement(XElement warningsEl) }); } - // Memory grant warning + // Memory grant warning (from plan XML) — gate at 1 GB to avoid noise on small grants + // All values are in KB, consistent with MemoryGrantInfo element var memWarnEl = warningsEl.Element(Ns + "MemoryGrantWarning"); if (memWarnEl != null) { @@ -1673,12 +1674,17 @@ private static List ParseWarningsFromElement(XElement warningsEl) var requested = ParseLong(memWarnEl.Attribute("RequestedMemory")?.Value); var granted = ParseLong(memWarnEl.Attribute("GrantedMemory")?.Value); var maxUsed = ParseLong(memWarnEl.Attribute("MaxUsedMemory")?.Value); - result.Add(new PlanWarning + if (granted >= 1048576) // 1 GB in KB { - WarningType = "Memory Grant", - Message = $"{kind}: Requested {requested:N0} KB, Granted {granted:N0} KB, Used {maxUsed:N0} KB", - Severity = PlanWarningSeverity.Warning - }); + var grantedMB = granted / 1024.0; + var usedMB = maxUsed / 1024.0; + result.Add(new PlanWarning + { + WarningType = "Memory Grant", + Message = $"{kind}: Granted {grantedMB:N0} MB, Used {usedMB:N0} MB", + Severity = PlanWarningSeverity.Warning + }); + } } // Implicit conversions diff --git a/tests/PlanViewer.Core.Tests/PlanAnalyzerTests.cs b/tests/PlanViewer.Core.Tests/PlanAnalyzerTests.cs index 28ad002..33d0689 100644 --- a/tests/PlanViewer.Core.Tests/PlanAnalyzerTests.cs +++ b/tests/PlanViewer.Core.Tests/PlanAnalyzerTests.cs @@ -173,14 +173,15 @@ public void Rule08_ParallelSkew_DetectedOnHighRowScan() // --------------------------------------------------------------- [Fact] - public void Rule09a_ExcessiveMemoryGrant_DetectedInLazySpoolPlan() + public void Rule09a_ExcessiveMemoryGrant_SmallGrantSuppressed() { + // lazy_spool_plan has a 1 MB grant — well under the 1 GB threshold. + // The XML MemoryGrantWarning should be suppressed (not worth surfacing). var plan = PlanTestHelper.LoadAndAnalyze("lazy_spool_plan.sqlplan"); - // The parser may surface this as a plan-level warning from XML var allWarnings = PlanTestHelper.AllWarnings(plan); - Assert.Contains(allWarnings, w => - w.WarningType.Contains("Memory Grant") || w.WarningType == "Excessive Memory Grant"); + Assert.DoesNotContain(allWarnings, w => + w.WarningType == "Memory Grant"); } // ---------------------------------------------------------------