सबसे पहले, इससे पहले कि मैं कोड में वास्तविक निष्पादन योजना कैसे प्राप्त करूं और उन लोगों को ढूंढूं जो इंडेक्स की आवश्यकता की रिपोर्ट करते हैं, मैं आपको डेटाबेस इंजन ट्यूनिंग सलाहकार (डीटीए) , आप इसे सभी प्रश्नों की एक सूची खिला सकते हैं और यह आपको संभावित अनुक्रमणिका, आंकड़े, और कई अन्य चीजें बताते हुए संसाधित करेगा जो आपके प्रश्नों की योजना बनाने में सहायता कर सकती हैं।
इसे 1m+ प्रश्नों की सूची देने से भी बेहतर यह है कि आप सर्वर से वास्तविक प्रश्नों के साथ एक ट्रेस प्राप्त कर सकते हैं जो चल रहे हैं और यह उन प्रश्नों पर ध्यान केंद्रित करेगा जो सबसे अधिक समय ले रहे हैं।
अपने मूल प्रश्न का उत्तर देने के लिए आपको SET STATISTICS XML ON
कनेक्शन की शुरुआत में, यह आपको एक्सएमएल डेटा देगा जो आपके द्वारा दिखाया गया जीयूआई आधारित है। (प्राप्त करने के बारे में अधिक जानकारी के लिए यहां देखें योजनाएं
) एक बार जब आप ऐसा कर लेते हैं तो आपके प्रश्न पहले कॉलम की पहली पंक्ति में योजना के लिए एक्सएमएल युक्त अतिरिक्त परिणाम सेट के साथ वापस आ जाएंगे।
यहाँ एक त्वरित और गंदा कार्य है जो ऐसा करता है।
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 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
. नाम के सभी नोड्स को खोजने के लिए ।