mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-15 17:23:32 -05:00
* Adding recommendations * Adding raw graph type in execution plan graph contracts * Fixing function name and concising string formatting * Converting localized string to a function * Using better names in contract props Formatting names in a better way * Getting rid of unnecessary getter, setters and private props * Fixing localized strings, comments and imports * Fixing some contracts * Fixing csproj formatting * Fixing var names * Fixing xml comments
127 lines
5.1 KiB
C#
127 lines
5.1 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using Microsoft.SqlTools.ServiceLayer.ShowPlan.ShowPlanGraph;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.ShowPlan
|
|
{
|
|
public class ShowPlanGraphUtils
|
|
{
|
|
public static List<ExecutionPlanGraph> CreateShowPlanGraph(string xml, string fileName)
|
|
{
|
|
ShowPlanGraph.ShowPlanGraph[] graphs = ShowPlanGraph.ShowPlanGraph.ParseShowPlanXML(xml, ShowPlanGraph.ShowPlanType.Unknown);
|
|
return graphs.Select(g => new ExecutionPlanGraph
|
|
{
|
|
Root = ConvertShowPlanTreeToExecutionPlanTree(g.Root),
|
|
Query = g.Statement,
|
|
GraphFile = new ExecutionPlanGraphFile
|
|
{
|
|
GraphFileContent = xml,
|
|
GraphFileType = "xml"
|
|
},
|
|
Recommendations = ParseRecommendations(g, fileName)
|
|
}).ToList();
|
|
}
|
|
|
|
private static ExecutionPlanNode ConvertShowPlanTreeToExecutionPlanTree(Node currentNode)
|
|
{
|
|
return new ExecutionPlanNode
|
|
{
|
|
Type = currentNode.Operation.Image,
|
|
Cost = currentNode.Cost,
|
|
SubTreeCost = currentNode.SubtreeCost,
|
|
Description = currentNode.Description,
|
|
Subtext = currentNode.GetDisplayLinesOfText(),
|
|
RelativeCost = currentNode.RelativeCost,
|
|
Properties = GetProperties(currentNode.Properties),
|
|
Children = currentNode.Children.Select(x => ConvertShowPlanTreeToExecutionPlanTree(x)).ToList(),
|
|
Edges = currentNode.Edges.Select(x => ConvertShowPlanEdgeToExecutionPlanEdge(x)).ToList(),
|
|
Name = currentNode.DisplayName,
|
|
ElapsedTimeInMs = currentNode.ElapsedTimeInMs
|
|
};
|
|
}
|
|
|
|
private static ExecutionPlanEdges ConvertShowPlanEdgeToExecutionPlanEdge(Edge edge)
|
|
{
|
|
return new ExecutionPlanEdges
|
|
{
|
|
RowCount = edge.RowCount,
|
|
RowSize = edge.RowSize,
|
|
Properties = GetProperties(edge.Properties)
|
|
};
|
|
}
|
|
|
|
private static List<ExecutionPlanGraphPropertyBase> GetProperties(PropertyDescriptorCollection props)
|
|
{
|
|
List<ExecutionPlanGraphPropertyBase> propsList = new List<ExecutionPlanGraphPropertyBase>();
|
|
foreach (PropertyValue prop in props)
|
|
{
|
|
var complexProperty = prop.Value as ExpandableObjectWrapper;
|
|
if (complexProperty == null)
|
|
{
|
|
var propertyValue = prop.DisplayValue;
|
|
propsList.Add(new ExecutionPlanGraphProperty()
|
|
{
|
|
Name = prop.DisplayName,
|
|
Value = propertyValue,
|
|
ShowInTooltip = prop.IsBrowsable,
|
|
DisplayOrder = prop.DisplayOrder,
|
|
IsLongString = prop.IsLongString,
|
|
});
|
|
}
|
|
else
|
|
{
|
|
var propertyValue = GetProperties(complexProperty.Properties);
|
|
propsList.Add(new NestedExecutionPlanGraphProperty()
|
|
{
|
|
Name = prop.DisplayName,
|
|
Value = propertyValue,
|
|
ShowInTooltip = prop.IsBrowsable,
|
|
DisplayOrder = prop.DisplayOrder,
|
|
IsLongString = prop.IsLongString,
|
|
});
|
|
}
|
|
|
|
}
|
|
return propsList;
|
|
}
|
|
|
|
private static List<ExecutionPlanRecommendation> ParseRecommendations(ShowPlanGraph.ShowPlanGraph g, string fileName)
|
|
{
|
|
return g.Description.MissingIndices.Select(mi => new ExecutionPlanRecommendation
|
|
{
|
|
DisplayString = mi.MissingIndexCaption,
|
|
Query = mi.MissingIndexQueryText,
|
|
QueryWithDescription = ParseMissingIndexQueryText(fileName, mi.MissingIndexImpact, mi.MissingIndexDatabase, mi.MissingIndexQueryText)
|
|
}).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates query file text for the recommendations. It has the missing index query along with some lines of description.
|
|
/// </summary>
|
|
/// <param name="fileName">query file name that has generated the plan</param>
|
|
/// <param name="impact">impact of the missing query on performance</param>
|
|
/// <param name="database">database name to create the missing index in</param>
|
|
/// <param name="query">actual query that will be used to create the missing index</param>
|
|
/// <returns></returns>
|
|
private static string ParseMissingIndexQueryText(string fileName, string impact, string database, string query)
|
|
{
|
|
return $@"{SR.MissingIndexDetailsTitle(fileName, impact)}
|
|
|
|
/*
|
|
{string.Format("USE {0}", database)}
|
|
GO
|
|
{string.Format("{0}", query)}
|
|
GO
|
|
*/
|
|
";
|
|
}
|
|
}
|
|
}
|