<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'Query Optimizer' and 'Execution Plans'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=Query+Optimizer,Execution+Plans&amp;orTags=0</link><description>Search results matching tags 'Query Optimizer' and 'Execution Plans'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>The Query Optimizer and Cost Estimation</title><link>http://sqlblog.com/blogs/ben_nevarez/archive/2010/02/17/the-query-optimizer-and-cost-estimation.aspx</link><pubDate>Thu, 18 Feb 2010 04:23:59 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:22413</guid><dc:creator>Ben Nevarez</dc:creator><description>&lt;p class="MsoNormal"&gt;Last year when I presented my session regarding the Query Optimizer at the PASS Summit and at a couple of local user groups, I was asked how the estimated CPU and I/O costs in an execution plan are calculated. Since Microsoft does not publish how these costs are calculated all I could say was that each operator cost depends on the operator algorithm and the cardinality estimation. &lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;This time I am working on a related project and I thought that perhaps I could look into this again to show as an example. But since there are dozens of operators I decided to start with a simple one: the Clustered Index Scan operator. So I captured dozens of XML plans, used XQuery to extract their cost information and after some analysis I was able to obtain a basic formula for this specific operator.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;To show this in an example, let us look at the largest table in AdventureWorks. Run the following query and look at the estimated CPU and I/O costs for the Clustered Index Scan operator&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal" style="margin:0in 0in 0pt;tab-stops:.5in;mso-layout-grid-align:none;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';mso-no-proof:yes;"&gt;select&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; &lt;span style="color:gray;"&gt;*&lt;/span&gt; &lt;span style="color:blue;"&gt;from&lt;/span&gt; Sales&lt;span style="color:gray;"&gt;.&lt;/span&gt;SalesOrderDetail      &lt;p&gt;&lt;/p&gt;   &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';mso-no-proof:yes;"&gt;where&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; LineTotal &lt;span style="color:gray;"&gt;=&lt;/span&gt; 35      &lt;p&gt;&lt;/p&gt;   &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal" style="text-align:center;" align="center"&gt;&lt;a href="http://sqlblog.com/blogs/ben_nevarez/clip_image002_22D67C8D.jpg"&gt;&lt;img title="clip_image002" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="366" alt="clip_image002" src="http://sqlblog.com/blogs/ben_nevarez/clip_image002_thumb_145C8DCB.jpg" width="342" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;For a Clustered Index Scan operator I observed that the CPU cost is 0.0001581 for the first record plus 0.0000011 for any additional record after that. In this specific case we have an estimated number of records of 121,317 so we can use 0.0001581 + 0.0000011 * (121317 – 1) or 0.133606 which is the value shown as Estimated CPU Cost. In a similar way, I noticed that the minimum I/O cost is 0.003125 for the first database page and then it grows in increments of 0.00074074 for every additional page. Since this operator scans the entire table I can use the following query to find the number of database pages, which returns 1,234.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal" style="margin:0in 0in 0pt;tab-stops:.5in;mso-layout-grid-align:none;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';mso-no-proof:yes;"&gt;select&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; in_row_data_page_count&lt;span style="color:gray;"&gt;,&lt;/span&gt; row_count       &lt;p&gt;&lt;/p&gt;   &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin:0in 0in 0pt;tab-stops:.5in;mso-layout-grid-align:none;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';mso-no-proof:yes;"&gt;from&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; &lt;span style="color:green;"&gt;sys&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:green;"&gt;dm_db_partition_stats       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin:0in 0in 0pt;tab-stops:.5in;mso-layout-grid-align:none;"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New';mso-no-proof:yes;"&gt;where&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; &lt;span style="color:fuchsia;"&gt;object_id&lt;/span&gt; &lt;span style="color:gray;"&gt;=&lt;/span&gt; &lt;span style="color:fuchsia;"&gt;object_id&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:red;"&gt;'Sales.SalesOrderDetail'&lt;/span&gt;&lt;span style="color:gray;"&gt;)       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin:0in 0in 0pt;tab-stops:.5in;mso-layout-grid-align:none;"&gt;&lt;span style="font-size:10pt;color:gray;font-family:'Courier New';mso-no-proof:yes;"&gt;and&lt;/span&gt;&lt;span style="font-size:10pt;font-family:'Courier New';mso-no-proof:yes;"&gt; index_id &lt;span style="color:gray;"&gt;=&lt;/span&gt; 1      &lt;p&gt;&lt;/p&gt;   &lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;In this case I have 0.003125 + 0.00074074 * (1234 – 1) or 0.916458 which is the value shown as Estimated I/O Cost.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;Finally, we add both costs, 0.133606 + 0.916458 to get 1.05006 which is the total estimated cost of the operator. In the same way, adding the cost of all the operators will give the total cost of the plan. In this case, the cost of the Clustered Index Scan, 1.05006, plus the cost of the first Compute Scalar operator, 0.01214, the second Compute Scalar operator, 0.01213, and the cost of the Filter operator, 0.0582322, will give the total cost of the plan, 1.13256, as shown next. &lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal" style="text-align:center;" align="center"&gt;&lt;a href="http://sqlblog.com/blogs/ben_nevarez/clip_image004_3FD1E1F5.jpg"&gt;&lt;img title="clip_image004" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="243" alt="clip_image004" src="http://sqlblog.com/blogs/ben_nevarez/clip_image004_thumb_7BE1C1BE.jpg" width="402" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;   &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/p&gt;  &lt;p class="MsoNormal"&gt;Finally, you can combine this with my previous post, Fooling the Query Optimizer at &lt;a href="http://sqlblog.com/blogs/ben_nevarez/archive/2010/01/13/fooling-the-query-optimizer.aspx"&gt;http://sqlblog.com/blogs/ben_nevarez/archive/2010/01/13/fooling-the-query-optimizer.aspx&lt;/a&gt;, to test with “bigger” tables by changing the number of records and pages of a table for testing purposes.&lt;/p&gt;</description></item></channel></rss>