June 10, 2011 at 12:53 pm
Beginning to use 2008 Exec. Plans for query tuning, but I'm running into some snags.
For example, I run the exec plan against a query, add an index, exec FREEPROCCACHE - but I still get the same results in the new execution plan.
Do I need to update statistics on that table in order to update the results in the exec plan?
June 10, 2011 at 12:57 pm
No. Are you sure the index is useful?
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
June 10, 2011 at 1:06 pm
Well, the exec plan recommended the index. The columns recommended are the exact fields referenced in the "where" criteria of the poorly performing query.
After re-running the plan, it's recommending the exact same index? Suppose I could order them up differently.....smallest to largest.
Suggestions? Thanks
June 10, 2011 at 2:16 pm
Don't reorder the columns in the key, it changes the index's usefulness.
Need to see query, index & execution plan to say more (and I assume since you say the exec plan recommended the index you are not using SQL 2000 despite posting in the SQL 2000 forums?)
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
June 10, 2011 at 3:02 pm
I was considering reordering the columns in the index - didn't realize that I was in the SQL 2000 area - did a 'find' on 'perf tuning' within the page.
This query is from an ERP app - just picked up the SQL through a trace. Below is the query and the index. Is the XML for the exec plan okay? Thanks
Query:
SELECT SUM(A.AMOUNTMST)
FROM CUSTTRANSOPEN A, CUSTTRANS B ,JSCUSTCREDITTABLE C
WHERE
(A.DATAAREAID='zz')
AND (B.DATAAREAID='zz')
AND ((C.DATAAREAID='zz') AND (((((B.ACCOUNTNUM='10200244')
AND (B.JSISCUSTCREDIT=0)) AND (A.REFRECID=B.RECID)) AND (C.VOUCHER=B.VOUCHER)) AND (C.CUSTCREDITSTATUS=0)))
INDEX:
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[CUSTTRANS] ([ACCOUNTNUM],[DATAAREAID],[JSISCUSTCREDIT])
exec plan XML:
<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.0.2531.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementCompId="1" StatementEstRows="1" StatementId="1" StatementOptmLevel="FULL" StatementSubTreeCost="4.36502" StatementText="SELECT SUM(A.AMOUNTMST) FROM CUSTTRANSOPEN A, CUSTTRANS B ,JSCUSTCREDITTABLE C WHERE (A.DATAAREAID='HS') AND (B.DATAAREAID='HS') AND ((C.DATAAREAID='HS') AND (((((B.ACCOUNTNUM='10200244') AND (B.JSISCUSTCREDIT=0)) AND (A.REFRECID=B.RECID)) AND (C.VOUCHER=B.VOUCHER)) AND (C.CUSTCREDITSTATUS=0)))" StatementType="SELECT" QueryHash="0x8A5103D79668D287" QueryPlanHash="0x03EAF544E5DDE02A">
<StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
<QueryPlan CachedPlanSize="72" CompileTime="32" CompileCPU="32" CompileMemory="1808">
<MissingIndexes>
<MissingIndexGroup Impact="74.2641">
<MissingIndex Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]">
<ColumnGroup Usage="EQUALITY">
<Column Name="[ACCOUNTNUM]" ColumnId="1" />
<Column Name="[DATAAREAID]" ColumnId="71" />
<Column Name="[JSISCUSTCREDIT]" ColumnId="74" />
</ColumnGroup>
</MissingIndex>
</MissingIndexGroup>
</MissingIndexes>
<RelOp AvgRowSize="24" EstimateCPU="0.00172162" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Compute Scalar" EstimatedTotalSubtreeCost="4.36502">
<OutputList>
<ColumnReference Column="Expr1008" />
</OutputList>
<ComputeScalar>
<DefinedValues>
<DefinedValue>
<ColumnReference Column="Expr1008" />
<ScalarOperator ScalarString="CASE WHEN [Expr1017]=(0) THEN NULL ELSE [Expr1018] END">
<IF>
<Condition>
<ScalarOperator>
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Column="Expr1017" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="(0)" />
</ScalarOperator>
</Compare>
</ScalarOperator>
</Condition>
<Then>
<ScalarOperator>
<Const ConstValue="NULL" />
</ScalarOperator>
</Then>
<Else>
<ScalarOperator>
<Identifier>
<ColumnReference Column="Expr1018" />
</Identifier>
</ScalarOperator>
</Else>
</IF>
</ScalarOperator>
</DefinedValue>
</DefinedValues>
<RelOp AvgRowSize="24" EstimateCPU="0.00172162" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="1" LogicalOp="Aggregate" NodeId="1" Parallel="false" PhysicalOp="Stream Aggregate" EstimatedTotalSubtreeCost="4.36502">
<OutputList>
<ColumnReference Column="Expr1017" />
<ColumnReference Column="Expr1018" />
</OutputList>
<StreamAggregate>
<DefinedValues>
<DefinedValue>
<ColumnReference Column="Expr1017" />
<ScalarOperator ScalarString="Count(*)">
<Aggregate AggType="countstar" Distinct="false" />
</ScalarOperator>
</DefinedValue>
<DefinedValue>
<ColumnReference Column="Expr1018" />
<ScalarOperator ScalarString="SUM([MY_MOCK].[dbo].[CUSTTRANSOPEN].[AMOUNTMST] as [A].[AMOUNTMST])">
<Aggregate AggType="SUM" Distinct="false">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="AMOUNTMST" />
</Identifier>
</ScalarOperator>
</Aggregate>
</ScalarOperator>
</DefinedValue>
</DefinedValues>
<RelOp AvgRowSize="20" EstimateCPU="0.205059" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="2868.53" LogicalOp="Inner Join" NodeId="2" Parallel="false" PhysicalOp="Hash Match" EstimatedTotalSubtreeCost="4.3633">
<OutputList>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="AMOUNTMST" />
</OutputList>
<MemoryFractions Input="0.165803" Output="1" />
<Hash>
<DefinedValues />
<HashKeysBuild>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="RECID" />
</HashKeysBuild>
<HashKeysProbe>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="REFRECID" />
</HashKeysProbe>
<ProbeResidual>
<ScalarOperator ScalarString="[MY_MOCK].[dbo].[CUSTTRANSOPEN].[REFRECID] as [A].[REFRECID]=[MY_MOCK].[dbo].[CUSTTRANS].[RECID] as .[RECID]">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="REFRECID" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="RECID" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
</ProbeResidual>
<RelOp AvgRowSize="15" EstimateCPU="0.420538" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="3285.31" LogicalOp="Inner Join" NodeId="3" Parallel="false" PhysicalOp="Hash Match" EstimatedTotalSubtreeCost="3.78128">
<OutputList>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="RECID" />
</OutputList>
<MemoryFractions Input="1" Output="0.834197" />
<Hash>
<DefinedValues />
<HashKeysBuild>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="VOUCHER" />
</HashKeysBuild>
<HashKeysProbe>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="VOUCHER" />
</HashKeysProbe>
<ProbeResidual>
<ScalarOperator ScalarString="[MY_MOCK].[dbo].[JSCUSTCREDITTABLE].[VOUCHER] as [C].[VOUCHER]=[MY_MOCK].[dbo].[CUSTTRANS].[VOUCHER] as .[VOUCHER]">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="VOUCHER" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="VOUCHER" />
</Identifier>
</ScalarOperator>
</Compare>
</ScalarOperator>
</ProbeResidual>
<RelOp AvgRowSize="37" EstimateCPU="0.0038233" EstimateIO="0.109802" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="3310.26" LogicalOp="Clustered Index Seek" NodeId="4" Parallel="false" PhysicalOp="Clustered Index Seek" EstimatedTotalSubtreeCost="0.113625" TableCardinality="4298">
<OutputList>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="VOUCHER" />
</OutputList>
<IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="VOUCHER" />
</DefinedValue>
</DefinedValues>
<Object Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Index="[I_30465CREDITID]" Alias="[C]" IndexKind="Clustered" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<Prefix ScanType="EQ">
<RangeColumns>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="DATAAREAID" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="N'HS'">
<Const ConstValue="N'HS'" />
</ScalarOperator>
</RangeExpressions>
</Prefix>
</SeekKeys>
</SeekPredicateNew>
</SeekPredicates>
<Predicate>
<ScalarOperator ScalarString="[MY_MOCK].[dbo].[JSCUSTCREDITTABLE].[CUSTCREDITSTATUS] as [C].[CUSTCREDITSTATUS]=(0)">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[JSCUSTCREDITTABLE]" Alias="[C]" Column="CUSTCREDITSTATUS" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="(0)" />
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</IndexScan>
</RelOp>
<RelOp AvgRowSize="46" EstimateCPU="0.0535981" EstimateIO="3.16859" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="48582.9" LogicalOp="Clustered Index Seek" NodeId="5" Parallel="false" PhysicalOp="Clustered Index Seek" EstimatedTotalSubtreeCost="3.22219" TableCardinality="1018090">
<OutputList>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="VOUCHER" />
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="RECID" />
</OutputList>
<IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="VOUCHER" />
</DefinedValue>
<DefinedValue>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="RECID" />
</DefinedValue>
</DefinedValues>
<Object Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Index="[I_078ACCOUNTDATEIDX]" Alias="" IndexKind="Clustered" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<Prefix ScanType="EQ">
<RangeColumns>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="DATAAREAID" />
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="ACCOUNTNUM" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="N'HS'">
<Const ConstValue="N'HS'" />
</ScalarOperator>
<ScalarOperator ScalarString="N'10200244'">
<Const ConstValue="N'10200244'" />
</ScalarOperator>
</RangeExpressions>
</Prefix>
</SeekKeys>
</SeekPredicateNew>
</SeekPredicates>
<Predicate>
<ScalarOperator ScalarString="[MY_MOCK].[dbo].[CUSTTRANS].[JSISCUSTCREDIT] as .[JSISCUSTCREDIT]=(0)">
<Compare CompareOp="EQ">
<ScalarOperator>
<Identifier>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANS]" Alias="" Column="JSISCUSTCREDIT" />
</Identifier>
</ScalarOperator>
<ScalarOperator>
<Const ConstValue="(0)" />
</ScalarOperator>
</Compare>
</ScalarOperator>
</Predicate>
</IndexScan>
</RelOp>
</Hash>
</RelOp>
<RelOp AvgRowSize="28" EstimateCPU="0.0219673" EstimateIO="0.354996" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="19827.6" LogicalOp="Clustered Index Seek" NodeId="7" Parallel="false" PhysicalOp="Clustered Index Seek" EstimatedTotalSubtreeCost="0.376964" TableCardinality="41319">
<OutputList>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="AMOUNTMST" />
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="REFRECID" />
</OutputList>
<IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="AMOUNTMST" />
</DefinedValue>
<DefinedValue>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="REFRECID" />
</DefinedValue>
</DefinedValues>
<Object Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Index="[I_865ACCOUNTDATEIDX]" Alias="[A]" IndexKind="Clustered" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<Prefix ScanType="EQ">
<RangeColumns>
<ColumnReference Database="[MY_MOCK]" Schema="[dbo]" Table="[CUSTTRANSOPEN]" Alias="[A]" Column="DATAAREAID" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="N'HS'">
<Const ConstValue="N'HS'" />
</ScalarOperator>
</RangeExpressions>
</Prefix>
</SeekKeys>
</SeekPredicateNew>
</SeekPredicates>
</IndexScan>
</RelOp>
</Hash>
</RelOp>
</StreamAggregate>
</RelOp>
</ComputeScalar>
</RelOp>
</QueryPlan>
</StmtSimple>
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
June 10, 2011 at 4:27 pm
Save the file as a .sqlplan and attach it.
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
June 11, 2011 at 4:50 am
One piece of advice. You're writing your queries using the ANSI 89 standard on joins. Don't do that. As soon as you get to outer joins you're going to have an issue because that method is not supported in 2008. Instead of putting listing the tables and then putting the join criteria in the WHERE clause, use this method:
SELECT...
FROM TableA as a
JOIN TableB as b
ON a.ID = b.ID
JOIN TableC as c
ON b.whatever = c.whatever
WHERE...
Then you put the filtering criteria in the WHERE clause.
"The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
- Theodore Roosevelt
Author of:
SQL Server Execution Plans
SQL Server Query Performance Tuning
June 13, 2011 at 8:54 am
GilaMonster (6/10/2011)
Save the file as a .sqlplan and attach it.
Sorry, didn't see the attachment option initially. The plan is attached.
June 13, 2011 at 9:01 am
Grant Fritchey (6/11/2011)
One piece of advice. You're writing your queries using the ANSI 89 standard on joins. Don't do that. As soon as you get to outer joins you're going to have an issue because that method is not supported in 2008. Instead of putting listing the tables and then putting the join criteria in the WHERE clause, use this method:
SELECT...
FROM TableA as a
JOIN TableB as b
ON a.ID = b.ID
JOIN TableC as c
ON b.whatever = c.whatever
WHERE...
Then you put the filtering criteria in the WHERE clause.
This SQL is written into my MS DAX ERP system for a customer select. I am looking to speed it up with an index.
I knew the query was using older syntax for joining, but did not know the term for it. Thanks for the clarification.
June 13, 2011 at 9:21 am
Since that's an estimated plan not an actual plan it's hard to know for sure, but it looks like the table has a cardinality estimate of about 1 million rows and you're returning 50k rows from it. That's probably not quite selective enough for an index to really help. That's why the plan didn't change.
With all the data coming back ordered out of those seeks & scans I'm surprised it didn't use merge joins considering the data involved. I'm generally anti-hint, but you might try using a merge join hint, just out of sheer curiousity.
Other than that, it looks like your data isn't as selective as it needs to be at .5% of the data in the table. At least that's the indication. Of those three columns, which is the most selective, has the most unique values? If it's not the first one, then as you suggested, you might try rearranging them to see what you get then.
"The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
- Theodore Roosevelt
Author of:
SQL Server Execution Plans
SQL Server Query Performance Tuning
June 23, 2011 at 6:14 pm
Grant Fritchey (6/13/2011)
Since that's an estimated plan not an actual plan it's hard to know for sure, but it looks like the table has a cardinality estimate of about 1 million rows and you're returning 50k rows from it. That's probably not quite selective enough for an index to really help. That's why the plan didn't change.With all the data coming back ordered out of those seeks & scans I'm surprised it didn't use merge joins considering the data involved. I'm generally anti-hint, but you might try using a merge join hint, just out of sheer curiousity.
Other than that, it looks like your data isn't as selective as it needs to be at .5% of the data in the table. At least that's the indication. Of those three columns, which is the most selective, has the most unique values? If it's not the first one, then as you suggested, you might try rearranging them to see what you get then.
I found a code profiler (trace) within the app and was able to catch sql statements that weren't showing up in the sql trace. With this tool I found the statement that needed the index. After adding the appropriate index, the query was much faster...
June 24, 2011 at 2:51 am
You will find that most of Dynamic's is written in cursors, we have the exact same issue here. Was talking about this yesterday on a different thread.
You need to do all Dynamics "profiler" via the Dynamics app as all you will usually see is FETCH API_CURSOR000000000000000123 etc not the actual T-SQL within the cursor.
I had a powerpoint which went into some detail on perf monitoring Dynamics, once I find it again I will upload it.
EDIT, found the powerpoint
June 24, 2011 at 11:47 am
anthony.green (6/24/2011)
You will find that most of Dynamic's is written in cursors, we have the exact same issue here. Was talking about this yesterday on a different thread.You need to do all Dynamics "profiler" via the Dynamics app as all you will usually see is FETCH API_CURSOR000000000000000123 etc not the actual T-SQL within the cursor.
I had a powerpoint which went into some detail on perf monitoring Dynamics, once I find it again I will upload it.
EDIT, found the powerpoint
WOW! Thanks
How long have you been working with Dynamics and what verison(s)?
June 27, 2011 at 2:09 am
Just Dynamics 2009 but been working with it now for over a year, only recently got more and more into the tuning as it has only just taken off throughout the business in the last 8 weeks.
Viewing 14 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic. Login to reply