diff --git a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/Contracts/ExecutionPlanGraph.cs b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/Contracts/ExecutionPlanGraph.cs index 7744840b..49a3ea9f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/Contracts/ExecutionPlanGraph.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/Contracts/ExecutionPlanGraph.cs @@ -63,7 +63,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts /// public double RelativeCost { get; set; } /// - /// Time take by the node operation in milliseconds + /// Time taken by the node operation in milliseconds /// public long? ElapsedTimeInMs { get; set; } /// @@ -92,6 +92,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts /// Top operations table data for the node /// public List TopOperationsData { get; set; } + /// + /// The cost metrics for the node. + /// + public List CostMetrics { get; set; } + } + + public class CostMetric + { + /// + /// Name of the cost metric + /// + public string Name { get; set; } + /// + /// The value for the cost metric + /// + public string Value { get; set; } } public class ExecutionPlanGraphPropertyBase diff --git a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ExecutionPlanGraphUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ExecutionPlanGraphUtils.cs index 905b4d48..0e7c8d4b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ExecutionPlanGraphUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ExecutionPlanGraphUtils.cs @@ -33,8 +33,40 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan }).ToList(); } + private static void ParseCostMetricProperty(List costMetrics, string name, PropertyValue? property) + { + if (property != null) + { + var costMetric = new CostMetric() + { + Name = name, + Value = ExecutionPlanGraphUtils.GetPropertyDisplayValue(property) + }; + + costMetrics.Add(costMetric); + } + } + public static ExecutionPlanNode ConvertShowPlanTreeToExecutionPlanTree(Node currentNode) { + var costMetrics = new List(); + + var elapsedCpuTimeInMs = currentNode.ElapsedCpuTimeInMs; + if (elapsedCpuTimeInMs.HasValue) + { + var costMetric = new CostMetric() + { + Name = "ElapsedCpuTime", + Value = $"{elapsedCpuTimeInMs.Value}" + }; + costMetrics.Add(costMetric); + } + + ExecutionPlanGraphUtils.ParseCostMetricProperty(costMetrics, "EstimateRowsAllExecs", currentNode.Properties["EstimateRowsAllExecs"] as PropertyValue); + ExecutionPlanGraphUtils.ParseCostMetricProperty(costMetrics, "EstimatedRowsRead", currentNode.Properties["EstimatedRowsRead"] as PropertyValue); + ExecutionPlanGraphUtils.ParseCostMetricProperty(costMetrics, "ActualRows", currentNode.Properties["ActualRows"] as PropertyValue); + ExecutionPlanGraphUtils.ParseCostMetricProperty(costMetrics, "ActualRowsRead", currentNode.Properties["ActualRowsRead"] as PropertyValue); + return new ExecutionPlanNode { ID = currentNode.ID, @@ -52,7 +84,8 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan Badges = GenerateNodeOverlay(currentNode), Name = currentNode.DisplayName, ElapsedTimeInMs = currentNode.ElapsedTimeInMs, - TopOperationsData = ParseTopOperationsData(currentNode) + TopOperationsData = ParseTopOperationsData(currentNode), + CostMetrics = costMetrics }; } @@ -134,6 +167,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan propertyDataType = PropertyValueDataType.String; break; } + propsList.Add(new ExecutionPlanGraphProperty() { Name = prop.DisplayName, @@ -412,8 +446,13 @@ GO "; } - private static string GetPropertyDisplayValue(PropertyValue property) + private static string GetPropertyDisplayValue(PropertyValue? property) { + if (property == null) + { + return string.Empty; + } + try { // Get the property value. @@ -421,7 +460,7 @@ GO if (propertyValue == null) { - return String.Empty; + return string.Empty; } // Convert the property value to the text. @@ -430,7 +469,7 @@ GO catch (Exception e) { Logger.Write(TraceEventType.Error, e.ToString()); - return String.Empty; + return string.Empty; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/Node.cs b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/Node.cs index 48a05dd6..4643d712 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/Node.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ExecutionPlan/ShowPlan/Node.cs @@ -501,6 +501,26 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.ShowPlan } } + public long? ElapsedCpuTimeInMs + { + get + { + long? time = null; + var actualStatsWrapper = this["ActualTimeStatistics"] as ExpandableObjectWrapper; + if (actualStatsWrapper != null) + { + var counters = actualStatsWrapper["ActualCPUms"] as RunTimeCounters; + if (counters != null) + { + var elapsedTime = counters.MaxCounter; + long ticks = (long)elapsedTime * TimeSpan.TicksPerMillisecond; + time = new DateTime(ticks).Millisecond; + } + } + return time; + } + } + /// /// ENU name for Logical Operator ///