diff --git a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs index 836a377..65b5b87 100644 --- a/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs +++ b/src/PlanViewer.App/Controls/PlanViewerControl.axaml.cs @@ -2800,9 +2800,12 @@ void AddRow(string label, string value, string? color = null) rowIndex++; } - // Efficiency thresholds: white >= 80%, yellow >= 60%, orange >= 40%, red < 40% - static string EfficiencyColor(double pct) => pct >= 80 ? "#E4E6EB" - : pct >= 60 ? "#FFD700" : pct >= 40 ? "#FFB347" : "#E57373"; + // Efficiency thresholds: white >= 40%, orange >= 20%, red < 20%. + // Loosened per Joe's feedback (#215 C1): for memory grants, moderate + // utilization (e.g. 60%) is fine — operators can spill near their max, + // so we shouldn't flag anything above a real over-grant threshold. + static string EfficiencyColor(double pct) => pct >= 40 ? "#E4E6EB" + : pct >= 20 ? "#FFB347" : "#E57373"; // Runtime stats (actual plans) if (statement.QueryTimeStats != null) @@ -2815,6 +2818,11 @@ static string EfficiencyColor(double pct) => pct >= 80 ? "#E4E6EB" AddRow("UDF elapsed", $"{statement.QueryUdfElapsedTimeMs:N0}ms"); } + // Compile time — plan-level property (category B). Show regardless of + // threshold so it's always visible, not just when Rule 19 fires. + if (statement.CompileTimeMs > 0) + AddRow("Compile", $"{statement.CompileTimeMs:N0}ms"); + // Memory grant — color by utilization percentage if (statement.MemoryGrant != null) { diff --git a/src/PlanViewer.App/PlanViewer.App.csproj b/src/PlanViewer.App/PlanViewer.App.csproj index 815d970..d4b5e1d 100644 --- a/src/PlanViewer.App/PlanViewer.App.csproj +++ b/src/PlanViewer.App/PlanViewer.App.csproj @@ -6,7 +6,7 @@ app.manifest EDD.ico true - 1.7.4 + 1.7.5 Erik Darling Darling Data LLC Performance Studio diff --git a/src/PlanViewer.Core/Output/HtmlExporter.cs b/src/PlanViewer.Core/Output/HtmlExporter.cs index fc9f54e..b38f131 100644 --- a/src/PlanViewer.Core/Output/HtmlExporter.cs +++ b/src/PlanViewer.Core/Output/HtmlExporter.cs @@ -308,6 +308,8 @@ private static void WriteRuntimeCard(StringBuilder sb, StatementResult stmt) WriteRow(sb, "CPU:Elapsed", ratio.ToString("N2")); } } + if (stmt.CompileTimeMs > 0) + WriteRow(sb, "Compile", $"{stmt.CompileTimeMs:N0} ms"); if (stmt.DegreeOfParallelism > 0) WriteRow(sb, "DOP", stmt.DegreeOfParallelism.ToString()); if (stmt.NonParallelReason != null) @@ -315,7 +317,7 @@ private static void WriteRuntimeCard(StringBuilder sb, StatementResult stmt) if (stmt.MemoryGrant != null && stmt.MemoryGrant.GrantedKB > 0) { var pctUsed = (double)stmt.MemoryGrant.MaxUsedKB / stmt.MemoryGrant.GrantedKB * 100; - var effClass = pctUsed >= 80 ? "eff-good" : pctUsed >= 40 ? "eff-warn" : "eff-bad"; + var effClass = pctUsed >= 40 ? "eff-good" : pctUsed >= 20 ? "eff-warn" : "eff-bad"; WriteRow(sb, "Memory", FormatKB(stmt.MemoryGrant.GrantedKB) + " granted"); sb.AppendLine($"
Used{FormatKB(stmt.MemoryGrant.MaxUsedKB)} ({pctUsed:N0}%)
"); } diff --git a/src/PlanViewer.Web/Pages/Index.razor b/src/PlanViewer.Web/Pages/Index.razor index 6d885d8..5b5b243 100644 --- a/src/PlanViewer.Web/Pages/Index.razor +++ b/src/PlanViewer.Web/Pages/Index.razor @@ -171,6 +171,13 @@ else } } + @if (ActiveStmt!.CompileTimeMs > 0) + { +
+ Compile + @ActiveStmt!.CompileTimeMs.ToString("N0") ms +
+ } @if (ActiveStmt!.DegreeOfParallelism > 0) {
@@ -188,7 +195,7 @@ else @if (ActiveStmt!.MemoryGrant != null && ActiveStmt!.MemoryGrant.GrantedKB > 0) { var pctUsed = (double)ActiveStmt!.MemoryGrant.MaxUsedKB / ActiveStmt!.MemoryGrant.GrantedKB * 100; - var effClass = pctUsed >= 80 ? "eff-good" : pctUsed >= 60 ? "eff-ok" : pctUsed >= 40 ? "eff-warn" : "eff-bad"; + var effClass = pctUsed >= 40 ? "eff-good" : pctUsed >= 20 ? "eff-warn" : "eff-bad";
Memory @FormatKB(ActiveStmt!.MemoryGrant.GrantedKB) granted