まず、コードで実際の実行プランを取得し、インデックスが必要であると報告するプランを見つける方法に入る前に、データベースエンジンチューニングアドバイザー(DTA) 、すべてのクエリのリストをフィードすると、それらが処理され、可能なインデックス、統計、およびクエリの計画に役立つその他の多くのことが通知されます。
100万以上のクエリのリストを提供するよりも、実行中の実際のクエリを含むトレースをサーバーから取得でき、最も時間がかかっているクエリに焦点を当てることができます。
元の質問に答えるには、SET STATISTICS XML ON
を追加する必要があります 接続の開始時に、これにより、表示したGUIが基づいているXMLデータが提供されます。 (取得の詳細については、こちらをご覧ください計画
)。これを行うと、クエリは最初の列の最初の行にプランのxmlを含む追加の結果セットとともに返されます。
これは、それを行う迅速で汚い関数です。
private static string GetXmlPlanForQuery(string queryText)
{
string result = null;
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand())
{
connection.Open();
command.Connection = connection;
//Enable the statistics.
command.CommandText = "SET STATISTICS XML ON";
command.ExecuteNonQuery();
//Run through the query, keeping the first row first column of the last result set.
command.CommandText = queryText;
using (var reader = command.ExecuteReader())
{
object lastValue = null;
do
{
if (reader.Read())
{
lastValue = reader.GetValue(0);
}
} while (reader.NextResult());
if (lastValue != null)
{
result = lastValue as string;
}
}
}
return result;
}
そして、これがクエリselect TOTAL_SALES from clients where ACTIVE = 0;
に対して返されたXMLです。 ローカルデータベースの1つで実行したこと。
<?xml version="1.0"?>
<ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.2" Build="11.0.5058.0">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementText="SELECT [TOTAL_SALES] FROM [clients] WHERE [ACTIVE][email protected]" StatementId="1" StatementCompId="1" StatementType="SELECT" RetrievedFromCache="false" StatementSubTreeCost="0.0767454" StatementEstRows="315" StatementOptmLevel="FULL" QueryHash="0x708AE72DD31A316" QueryPlanHash="0x214EA79FF76E6771" StatementOptmEarlyAbortReason="GoodEnoughPlanFound">
<StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false"/>
<QueryPlan DegreeOfParallelism="1" CachedPlanSize="16" CompileTime="1" CompileCPU="1" CompileMemory="192">
<MissingIndexes>
<MissingIndexGroup Impact="94.0522">
<MissingIndex Database="[exampleDb]" Schema="[dbo]" Table="[CLIENTS]">
<ColumnGroup Usage="EQUALITY">
<Column Name="[ACTIVE]" ColumnId="15"/>
</ColumnGroup>
<ColumnGroup Usage="INCLUDE">
<Column Name="[TOTAL_SALES]" ColumnId="18"/>
</ColumnGroup>
</MissingIndex>
</MissingIndexGroup>
</MissingIndexes>
<MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0"/>
<OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="830838" EstimatedPagesCached="207709" EstimatedAvailableDegreeOfParallelism="2"/>
<RelOp NodeId="0" PhysicalOp="Clustered Index Scan" LogicalOp="Clustered Index Scan" EstimateRows="315" EstimateIO="0.0749769" EstimateCPU="0.0017685" AvgRowSize="16" EstimatedTotalSubtreeCost="0.0767454" TableCardinality="1465" Parallel="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row">
<OutputList>
<ColumnReference Database="[exampleDb]" Schema="[dbo]" Table="[CLIENTS]" Column="TOTAL_SALES"/>
</OutputList>
<RunTimeInformation>
<RunTimeCountersPerThread Thread="0" ActualRows="315" ActualEndOfScans="1" ActualExecutions="1"/>
</RunTimeInformation>
<IndexScan Ordered="0" ForcedIndex="0" ForceScan="0" NoExpandHint="0">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[exampleDb]" Schema="[dbo]" Table="[CLIENTS]" Column="TOTAL_SALES"/>
</DefinedValue>
</DefinedValues>
<Object Database="[exampleDb]" Schema="[dbo]" Table="[CLIENTS]" Index="[imp_clpk_CLIENTS]" IndexKind="Clustered"/>
<Predicate>
<ScalarOperator ScalarString="[exampleDb].[dbo].[CLIENTS].[ACTIVE]=(0)">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[exampleDb]" Schema="[dbo]" Table="[CLIENTS]" Column="ACTIVE"/>
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="(0)"/>
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</IndexScan>
</RelOp>
<ParameterList>
<ColumnReference Column="@1" ParameterCompiledValue="(0)" ParameterRuntimeValue="(0)"/>
</ParameterList>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
さて、Microsoftは非常に優れているので、XMLにリストされている名前空間に移動します。
実際に.xsd
のコピーを取得できます フォーマットのために。次に、開発者のコマンドプロンプトからxsd showplanxml.xsd /classes
を実行できます。 showplanxml.cs
が表示されます XmlSerializer
で使用できます 。
これは、欠落しているインデックスに対してデバッガーブレークを実行する小さなサンプルプログラムです。
static void Main(string[] args)
{
string result = GetXmlPlanForQuery("select TOTAL_SALES from clients where ACTIVE = 0;");
XmlSerializer ser = new XmlSerializer(typeof(ShowPlanXML));
var plan = (ShowPlanXML)ser.Deserialize(new StringReader(result));
var missingIndexes =
plan.BatchSequence.SelectMany(x => x)
.SelectMany(x => x.Items)
.OfType<StmtSimpleType>()
.Select(x => x.QueryPlan)
.Where(x => x.MissingIndexes != null && x.MissingIndexes.Any());
foreach (var queryPlan in missingIndexes)
{
//This will hit for each statement in the query that was missing a index, check queryPlan.MissingIndexes to see the indexes that are missing.
Debugger.Break();
}
Console.WriteLine("Done");
Console.ReadLine();
}
XmlSerializerを使用してクラスに脱セラル化しましたが、これをXDocumentに簡単にロードしてから、XPathを使用することもできます。
MissingIndex
という名前のすべてのノードを検索します 。