Additional Execution Plan Node Properties for Highlighting Expensive Operators (#1683)

* Adds cost metric information to the node.

* Gets the elapsed CPU time by the node operation

* Renames DTO property to row metrics

* Removes unused class

* Simplify checks for row property values

* Cleans up model for node cost metrics

* Removes duplicate code

* Switching to primitive type empty string

* Code review changes
This commit is contained in:
Lewis Sanchez
2022-09-29 13:09:37 -07:00
committed by GitHub
parent 7c5d48b111
commit ddfc86fe04
3 changed files with 80 additions and 5 deletions

View File

@@ -63,7 +63,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts
/// </summary>
public double RelativeCost { get; set; }
/// <summary>
/// Time take by the node operation in milliseconds
/// Time taken by the node operation in milliseconds
/// </summary>
public long? ElapsedTimeInMs { get; set; }
/// <summary>
@@ -92,6 +92,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan.Contracts
/// Top operations table data for the node
/// </summary>
public List<TopOperationsDataItem> TopOperationsData { get; set; }
/// <summary>
/// The cost metrics for the node.
/// </summary>
public List<CostMetric> CostMetrics { get; set; }
}
public class CostMetric
{
/// <summary>
/// Name of the cost metric
/// </summary>
public string Name { get; set; }
/// <summary>
/// The value for the cost metric
/// </summary>
public string Value { get; set; }
}
public class ExecutionPlanGraphPropertyBase

View File

@@ -33,8 +33,40 @@ namespace Microsoft.SqlTools.ServiceLayer.ExecutionPlan
}).ToList();
}
private static void ParseCostMetricProperty(List<CostMetric> 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<CostMetric>();
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;
}
}

View File

@@ -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;
}
}
/// <summary>
/// ENU name for Logical Operator
/// </summary>