diff --git a/Dashboard/Controls/PlanViewerControl.xaml.cs b/Dashboard/Controls/PlanViewerControl.xaml.cs index d212bb56..fc26e470 100644 --- a/Dashboard/Controls/PlanViewerControl.xaml.cs +++ b/Dashboard/Controls/PlanViewerControl.xaml.cs @@ -688,17 +688,17 @@ private void ShowPropertiesPanel(PlanNode node) // Timing if (node.ActualElapsedMs > 0 || node.ActualCPUMs > 0 - || node.UdfCpuTimeUs > 0 || node.UdfElapsedTimeUs > 0) + || node.UdfCpuTimeMs > 0 || node.UdfElapsedTimeMs > 0) { AddPropertySection("Actual Timing"); if (node.ActualElapsedMs > 0) AddPropertyRow("Elapsed Time", $"{node.ActualElapsedMs:N0} ms"); if (node.ActualCPUMs > 0) AddPropertyRow("CPU Time", $"{node.ActualCPUMs:N0} ms"); - if (node.UdfElapsedTimeUs > 0) - AddPropertyRow("UDF Elapsed", $"{node.UdfElapsedTimeUs:N0} us"); - if (node.UdfCpuTimeUs > 0) - AddPropertyRow("UDF CPU", $"{node.UdfCpuTimeUs:N0} us"); + if (node.UdfElapsedTimeMs > 0) + AddPropertyRow("UDF Elapsed", $"{node.UdfElapsedTimeMs:N0} ms"); + if (node.UdfCpuTimeMs > 0) + AddPropertyRow("UDF CPU", $"{node.UdfCpuTimeMs:N0} ms"); } // I/O diff --git a/Dashboard/Models/PlanModels.cs b/Dashboard/Models/PlanModels.cs index c6a6f87e..6ba0390c 100644 --- a/Dashboard/Models/PlanModels.cs +++ b/Dashboard/Models/PlanModels.cs @@ -272,8 +272,8 @@ public class PlanNode public string? ActionColumn { get; set; } public long ActualSegmentReads { get; set; } public long ActualSegmentSkips { get; set; } - public long UdfCpuTimeUs { get; set; } - public long UdfElapsedTimeUs { get; set; } + public long UdfCpuTimeMs { get; set; } + public long UdfElapsedTimeMs { get; set; } // XSD gap: RelOp-level metadata public bool GroupExecuted { get; set; } diff --git a/Dashboard/Services/PlanAnalyzer.cs b/Dashboard/Services/PlanAnalyzer.cs index df39baa9..2a32df34 100644 --- a/Dashboard/Services/PlanAnalyzer.cs +++ b/Dashboard/Services/PlanAnalyzer.cs @@ -221,15 +221,13 @@ private static void AnalyzeNode(PlanNode node, PlanStatement stmt) } // Rule 4: UDF timing — any node spending time in UDFs (actual plans) - if (node.UdfCpuTimeUs > 0 || node.UdfElapsedTimeUs > 0) + if (node.UdfCpuTimeMs > 0 || node.UdfElapsedTimeMs > 0) { - var cpuMs = node.UdfCpuTimeUs / 1000.0; - var elapsedMs = node.UdfElapsedTimeUs / 1000.0; node.Warnings.Add(new PlanWarning { WarningType = "UDF Execution", - Message = $"Scalar UDF executing on this operator. UDF elapsed: {elapsedMs:F1}ms, UDF CPU: {cpuMs:F1}ms", - Severity = elapsedMs >= 1000 ? PlanWarningSeverity.Critical : PlanWarningSeverity.Warning + Message = $"Scalar UDF executing on this operator. UDF elapsed: {node.UdfElapsedTimeMs:N0}ms, UDF CPU: {node.UdfCpuTimeMs:N0}ms", + Severity = node.UdfElapsedTimeMs >= 1000 ? PlanWarningSeverity.Critical : PlanWarningSeverity.Warning }); } diff --git a/Dashboard/Services/ShowPlanParser.cs b/Dashboard/Services/ShowPlanParser.cs index 6dfabd39..f367419e 100644 --- a/Dashboard/Services/ShowPlanParser.cs +++ b/Dashboard/Services/ShowPlanParser.cs @@ -1179,8 +1179,8 @@ private static PlanNode ParseRelOp(XElement relOpEl) node.ActualExecutionMode = actualExecMode; node.ActualSegmentReads = totalSegmentReads; node.ActualSegmentSkips = totalSegmentSkips; - node.UdfCpuTimeUs = totalUdfCpu; - node.UdfElapsedTimeUs = maxUdfElapsed; + node.UdfCpuTimeMs = totalUdfCpu; + node.UdfElapsedTimeMs = maxUdfElapsed; // Store per-thread data for parallel skew analysis foreach (var thread in runtimeEl.Elements(Ns + "RunTimeCountersPerThread")) diff --git a/Lite/Controls/PlanViewerControl.xaml.cs b/Lite/Controls/PlanViewerControl.xaml.cs index 9b17ad54..69e639da 100644 --- a/Lite/Controls/PlanViewerControl.xaml.cs +++ b/Lite/Controls/PlanViewerControl.xaml.cs @@ -698,17 +698,17 @@ private void ShowPropertiesPanel(PlanNode node) // Timing if (node.ActualElapsedMs > 0 || node.ActualCPUMs > 0 - || node.UdfCpuTimeUs > 0 || node.UdfElapsedTimeUs > 0) + || node.UdfCpuTimeMs > 0 || node.UdfElapsedTimeMs > 0) { AddPropertySection("Actual Timing"); if (node.ActualElapsedMs > 0) AddPropertyRow("Elapsed Time", $"{node.ActualElapsedMs:N0} ms"); if (node.ActualCPUMs > 0) AddPropertyRow("CPU Time", $"{node.ActualCPUMs:N0} ms"); - if (node.UdfElapsedTimeUs > 0) - AddPropertyRow("UDF Elapsed", $"{node.UdfElapsedTimeUs:N0} us"); - if (node.UdfCpuTimeUs > 0) - AddPropertyRow("UDF CPU", $"{node.UdfCpuTimeUs:N0} us"); + if (node.UdfElapsedTimeMs > 0) + AddPropertyRow("UDF Elapsed", $"{node.UdfElapsedTimeMs:N0} ms"); + if (node.UdfCpuTimeMs > 0) + AddPropertyRow("UDF CPU", $"{node.UdfCpuTimeMs:N0} ms"); } // I/O diff --git a/Lite/Models/PlanModels.cs b/Lite/Models/PlanModels.cs index 2da98c8c..323b0113 100644 --- a/Lite/Models/PlanModels.cs +++ b/Lite/Models/PlanModels.cs @@ -272,8 +272,8 @@ public class PlanNode public string? ActionColumn { get; set; } public long ActualSegmentReads { get; set; } public long ActualSegmentSkips { get; set; } - public long UdfCpuTimeUs { get; set; } - public long UdfElapsedTimeUs { get; set; } + public long UdfCpuTimeMs { get; set; } + public long UdfElapsedTimeMs { get; set; } // XSD gap: RelOp-level metadata public bool GroupExecuted { get; set; } diff --git a/Lite/Services/PlanAnalyzer.cs b/Lite/Services/PlanAnalyzer.cs index 0ae2fe8a..4fa41a5d 100644 --- a/Lite/Services/PlanAnalyzer.cs +++ b/Lite/Services/PlanAnalyzer.cs @@ -221,15 +221,13 @@ private static void AnalyzeNode(PlanNode node, PlanStatement stmt) } // Rule 4: UDF timing — any node spending time in UDFs (actual plans) - if (node.UdfCpuTimeUs > 0 || node.UdfElapsedTimeUs > 0) + if (node.UdfCpuTimeMs > 0 || node.UdfElapsedTimeMs > 0) { - var cpuMs = node.UdfCpuTimeUs / 1000.0; - var elapsedMs = node.UdfElapsedTimeUs / 1000.0; node.Warnings.Add(new PlanWarning { WarningType = "UDF Execution", - Message = $"Scalar UDF executing on this operator. UDF elapsed: {elapsedMs:F1}ms, UDF CPU: {cpuMs:F1}ms", - Severity = elapsedMs >= 1000 ? PlanWarningSeverity.Critical : PlanWarningSeverity.Warning + Message = $"Scalar UDF executing on this operator. UDF elapsed: {node.UdfElapsedTimeMs:N0}ms, UDF CPU: {node.UdfCpuTimeMs:N0}ms", + Severity = node.UdfElapsedTimeMs >= 1000 ? PlanWarningSeverity.Critical : PlanWarningSeverity.Warning }); } diff --git a/Lite/Services/ShowPlanParser.cs b/Lite/Services/ShowPlanParser.cs index 7cea60ef..02221b2b 100644 --- a/Lite/Services/ShowPlanParser.cs +++ b/Lite/Services/ShowPlanParser.cs @@ -1179,8 +1179,8 @@ private static PlanNode ParseRelOp(XElement relOpEl) node.ActualExecutionMode = actualExecMode; node.ActualSegmentReads = totalSegmentReads; node.ActualSegmentSkips = totalSegmentSkips; - node.UdfCpuTimeUs = totalUdfCpu; - node.UdfElapsedTimeUs = maxUdfElapsed; + node.UdfCpuTimeMs = totalUdfCpu; + node.UdfElapsedTimeMs = maxUdfElapsed; // Store per-thread data for parallel skew analysis foreach (var thread in runtimeEl.Elements(Ns + "RunTimeCountersPerThread"))