<?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>Tibor Karaszi : indexes</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx</link><description>Tags: indexes</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Another bugfix for sp_indexinfo</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/11/09/another-bugfix-for-sp-indexinfo.aspx</link><pubDate>Tue, 09 Nov 2010 08:26:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:30289</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/30289.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=30289</wfw:commentRss><description>JackMcC reported correctly at http://sqlblog.com/blogs/tibor_karaszi/archive/2009/02/18/sp-indexinfo-updated.aspx that sp_indexinfo will count rows double (or even tripple) if there are lob or row overflow allocations. Now fixed. Thanks Jack....(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2010/11/09/another-bugfix-for-sp-indexinfo.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=30289" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Tools/default.aspx">Tools</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Ola Hallengren's maint procedures now supports exclusions</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/08/09/ola-hallengren-s-maint-procedures-now-supports-exclusions.aspx</link><pubDate>Mon, 09 Aug 2010 05:02:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:27702</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/27702.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=27702</wfw:commentRss><description>Ola has a set of stored procedures to do maint operations, see http://ola.hallengren.com/ . Ola has now updated them to support exclusions or inclusions of tables, indexes or even whole schemas from index rebuild/reorg. Check out http://ola.hallengren.com/Documentation.html#SelectingIndexes...(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2010/08/09/ola-hallengren-s-maint-procedures-now-supports-exclusions.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=27702" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Backup/default.aspx">Backup</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Maintenance/default.aspx">Maintenance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/SQL+Server+Agent/default.aspx">SQL Server Agent</category></item><item><title>How selective do we need to be for an index to be used?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/04/01/how-selective-do-we-need-to-be-for-an-index-to-be-used.aspx</link><pubDate>Thu, 01 Apr 2010 07:39:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:23940</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>15</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/23940.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=23940</wfw:commentRss><description>You know the answer already: It depends. But I often see some percentage value quoted and the point of this post is to show that there is no such percentage value. To get the most out of this blog post, you should understand the basic structure for an...(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2010/04/01/how-selective-do-we-need-to-be-for-an-index-to-be-used.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=23940" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Adding a PK online?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2010/01/13/adding-a-pk-online.aspx</link><pubDate>Wed, 13 Jan 2010 08:53:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:20991</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/20991.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=20991</wfw:commentRss><description>I just read in a forum about a user who want to replikate a table, but the table doesn't have a PK. The table is pretty large, and having the table not available while adding the PK is undesireable. The table has a clustered index already, and there are...(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2010/01/13/adding-a-pk-online.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=20991" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Heaps, forwarding pointers, ALTER TABLE REBUILD and non-clustered indexes</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2009/08/28/heaps-forwarding-pointers-alter-table-rebuild-and-non-clustered-indexes.aspx</link><pubDate>Fri, 28 Aug 2009 10:15:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:16351</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>5</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/16351.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=16351</wfw:commentRss><description>Let's start with some background on forwarding pointers: Forwarding pointers in heaps can be a mess to get rid of. A forwarding pointer happens when you modify a row so that the row doesn't fit on the same page anymore. SQL Server moves the row to a new...(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2009/08/28/heaps-forwarding-pointers-alter-table-rebuild-and-non-clustered-indexes.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=16351" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/SQL+Server+2008/default.aspx">SQL Server 2008</category></item><item><title>Key count in sys[.]indexes</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2009/06/23/key-count-in-sys-indexes.aspx</link><pubDate>Tue, 23 Jun 2009 06:57:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:14851</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/14851.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=14851</wfw:commentRss><description>The old sysindexes table (as of 2005 implemented as a compatibility view) has a useful column named keycnt. This is supposed to give us the number of columns (keys) in the index. However, to make heads and tails out of the numbers, we need to understand...(&lt;a href="http://sqlblog.com/blogs/tibor_karaszi/archive/2009/06/23/key-count-in-sys-indexes.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=14851" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Match those types!</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2009/04/28/match-those-types.aspx</link><pubDate>Tue, 28 Apr 2009 10:30:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:13606</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>17</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/13606.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=13606</wfw:commentRss><description>&lt;P&gt;This is a recommendation I believe is worth repeating from time to time: Make sure you match data types when you write TSQL code. Else you in most cases end up with an implicit data type conversion. And in worst case, this conversion is performed at the column side - not the literal side of your query. What does that mean? Consider below:&lt;/P&gt;
&lt;P&gt;WHERE Col = Val&lt;/P&gt;
&lt;P&gt;Now, say that the types for above don't match. Val might be some parameter (to a stored procedure, for instance), a variable or a written value (literal). In any case, when SQL Server need to do some operation )like comparison like here) involving several values which aren't of the same type, then one of the values need to be converted so it is of the same type as the other. Which one is determined by the rules for "&lt;A title='Data Type Precendence"' href="http://msdn.microsoft.com/en-us/library/ms190309.aspx"&gt;Data Type Precedence&lt;/A&gt;". &lt;/P&gt;
&lt;P&gt;What we don't want is a conversion at the column side. Why? I would argue that an implicit conversion in the first place in many cases mean I misunderstood something about the types in my system and am on my way of producing a bug in my code. But having a more strict language is not the topic for this particular post (check out &lt;A title=this href="http://sommarskog.se/wishlist.html#strictchecks"&gt;this&lt;/A&gt;). My point here is that it is bad for performance reasons. Just yesterday and today I was &lt;A title="involved in a thread" href="http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/76f22f8a-53b1-4a30-a741-14da5cf539f1/"&gt;involved in a thread&lt;/A&gt; on the MSDN forum. Here's the repro script from that thread (slightly adjusted by me):&lt;/P&gt;
&lt;P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;USE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;tempdb &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;OBJECT_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'t'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;( &lt;BR&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&amp;nbsp;int&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;IDENTITY&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;10000001&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;NOT&amp;nbsp;NULL&amp;nbsp; &lt;BR&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;char&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;8&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;NULL &lt;BR&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c3&amp;nbsp;datetime&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NULL &lt;BR&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c3&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;TOP &lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;3000000&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'20080203'&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;master..spt_values&amp;nbsp;t1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;CROSS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;JOIN&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;master..spt_values&amp;nbsp;t2 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;CROSS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;JOIN&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;master..spt_values&amp;nbsp;t3 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;UPDATE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;CAST&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;AS&amp;nbsp;char&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;8&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;UNIQUE&amp;nbsp;CLUSTERED INDEX&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'10000009' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'10000008'&lt;/SPAN&gt;&lt;/CODE&gt; &lt;/P&gt;
&lt;P&gt;Don't bother too much about the first section. The relevant part here is that we have char(8) column with values which are unique (enforced by a unique index), on a table with three million rows.&lt;/P&gt;
&lt;P&gt;Now, before we dig deeper: What is the problem with above queries? The type do not match! The type in the table is char(8), but&amp;nbsp;literal is Unicode (the N before the string). Since nchar has higher precedence than char, then the column side needs to be converted to the value side. Not good. Try the code on SQL Server 2000 and you will see disaster. For me, STATISTICS IO gave 10755 logical reads for both queries, with Clustered Index Scan (which is the same as table scan). Hoover on the Clustered Index Scan icon and you will find "WHERE:(Convert([t].[c2])=[@1])". See how the conversion is done at the column side? This, my friend, mean that SQL Server cannot seek an index to find the rows. Ouch! That's just because we were a bit sloppy... Compare to below:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'10000009' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;t&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;c2&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'10000008'&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;You will find for both two above we have Clustered Index Seek with only three logical reads. That is a good improvement.&lt;/P&gt;
&lt;P&gt;OK, enough about SQL Server 2000, lets discuss 2008/2005. At first I couldn't see any difference between the two original queries (N'10000009' and N'10000008'). Both seemed to be instant, and the same execution plan for both. I even saved the execution plan as XML and used WinDiff to compare the xml files. No difference. But the poster said the "9" query was slower than the "8" query. I executed to text and had ctrl-E pressed for a while. And now I could see a difference. The flicker was quicker for the "8" version vs. the "9" version. I used Profiler and confirmed. The "9" version had consistently about 90000 microsecond duration where the "8" version had about 0 duration. This was also reflected in CPU usage, as shown by Profiler. I hoped to use Extended Events to find something deeper about this, but that didn't give me anything. Perhaps I didn't capture the relevant events, quite simply. X/Event experts are welcome to suggest event session configurations. :-)&lt;/P&gt;
&lt;P&gt;My guess for the difference is in the execution plan. You will see an index seek for both. That is good, since SQL Server nowadays potentially can use an index even if you end up with an implicit conversion at the column side. But you will see a few more operators in addition to the index seek. See that Constant Scalar followed by a Compute Scalar? My guess is that the built-in internal function used inside the Compute Scalar operator is more expensive for N'10000009' compared to N'10000008'. You can see this function if you use SET STATISTICS PROFILE ON. See the GetRangeThroughConvert() function. My guess is that the answer is the cost for this function. (Search the Internet for things like "Constant Scan" and "GetRangeThroughConvert" for other blog post on this topic.)&lt;/P&gt;
&lt;P&gt;The moral of the story? Here we have a cost which can be relevant in some cases, but we will only see this if we happen to execute our query with the right values and are very very observant. But we can eliminate all this mess this by using the right type for the column in the first place!&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=13606" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Tools/default.aspx">Tools</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Trace/default.aspx">Trace</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Troubleshooting/default.aspx">Troubleshooting</category></item><item><title>Sp_indexinfo updated</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2009/02/18/sp-indexinfo-updated.aspx</link><pubDate>Wed, 18 Feb 2009 17:30:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:11977</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>7</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/11977.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=11977</wfw:commentRss><description>&lt;P&gt;For a long while, I've had a few things I wanted to add for sp_indexinfo (my procedure which returns bunch of information for indexes).&lt;/P&gt;
&lt;P&gt;Dejan Sarka suggested adding XML indexes as well as making the column list look nicer. I've also had a request to add some documentation of what the procedure returns. Done. :-)&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp"&gt;http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp&lt;/A&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=11977" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Execution plan re-use, sp_executesql and TSQL variables</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2008/08/29/execution-plan-re-use-sp-executesql-and-tsql-variables.aspx</link><pubDate>Fri, 29 Aug 2008 06:34:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8644</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>7</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/8644.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=8644</wfw:commentRss><description>&lt;P&gt;Let me start by saying that the contents of this post is not very advanced. If you have read the excellent paper "Batch Compilation, Recompilation, and Plan Caching Issues in SQL Server 2005", &lt;A href="http://www.microsoft.com/technet/prodtechnol/sql/2005/recomp.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/2005/recomp.mspx&lt;/A&gt;&amp;nbsp;and understood it, you would already know below, and much more...&lt;/P&gt;
&lt;P&gt;I was reading a thread in the open newsgroups today (.tools, posted by Mike), about an advice that the SQL Server 2005 Database Engine Tuning Advisor&amp;nbsp;apparently gave. It advices to replace sp_executesql usage with declaring TSQL variables and using those in the WHERE clause. Translated to the Adventureworks database, it advices that instead of 1) below, we should use&amp;nbsp;2) below.&lt;/P&gt;
&lt;P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;&lt;FONT face=Arial color=#000000 size=2&gt;1)&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:#434343;"&gt;&lt;FONT color=#0000ff&gt;EXEC&amp;nbsp;&lt;/FONT&gt;&lt;SPAN style="COLOR:darkred;"&gt;sp_executesql&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'SELECT&amp;nbsp;FirstName,&amp;nbsp;LastName,&amp;nbsp;PersonType,&amp;nbsp;Title &lt;BR&gt;FROM&amp;nbsp;Person.Person &lt;BR&gt;WHERE&amp;nbsp;LastName&amp;nbsp;=&amp;nbsp;@P1'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'@P1&amp;nbsp;nvarchar(50)'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz'&lt;/SPAN&gt;&lt;FONT color=#000000&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:#434343;"&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;&lt;SPAN style="COLOR:blue;"&gt;&lt;FONT face=Arial color=#000000 size=2&gt;2)&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;NVARCHAR&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;50&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FirstName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;PersonType&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Title &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Person.Person &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1 &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;Now, I could not reproduce this (make DTA give me the same advice, to replace 1) with 2) ). Perhaps I misunderstood the poster in the group, it is because I'm running SQL Server 2008 DTA and engine, I'm not looking in the right place for that advice, my data isn't representative, I'm running the DTA with some other settings, etc..&amp;nbsp;But say that DTA does indeed give such an advice, would would it do that? To be honest, I don't know. It can hardly have enough information to determine whether 1) or 2) is the best choice.&lt;/P&gt;
&lt;P&gt;In short: Say we have an index on the LastName column and the name we look for can either be a very common name, like perhaps "Smith", or a not so common name, like "Karaszi". For the more common name, a table scan might be the best choice, where for the not-so-common name, an index seek it probably best thing. OK, a very simple example, but serves well for this discussion.&lt;/P&gt;
&lt;P&gt;Back to the difference between 1) and 2). There are potentially very important differences between the two:&lt;/P&gt;
&lt;P&gt;For 1), SQL Server will determine a plan based on the contents of the parameter when the plan is created. I.e., it can determine selectivity based on that and determine whether it is a good idea to use an index or not. The plan is then cached and can be re-used. But what if we for the first execution pass in something which is very selective, but typically we are &lt;STRONG&gt;not&lt;/STRONG&gt; very selective? Or the other way around? I,e, the plan for one case might not be optimal for some other case. This is where we have new optimizer hints in 2005 like OPTIMIZE FOR and the RECOMPILE hints. I will not go into details about these here, since I'm focusing on the differences between 1) and 2). See the white paper I mentioned, and of course Books Online, for more details.&lt;/P&gt;
&lt;P&gt;For 2), SQL Server (or rather: the optimizer) has no knowledge of the contents of the variable when the plan is produced. So it cannot use the statistics to determine selectivity. In above case, it instead uses density (stored with the statistics, assuming such exists for the column). Density is basically the 1/ number of unique values for the column(s). This might be a good representation for a typical lastname, but perhaps not too good for a very common or a very uncommon lastname. Now, in 2005, we have hints for these situations as well (RECOMPILE), but again, that is not the point here.&lt;/P&gt;
&lt;P&gt;In order for DTA to give the best advice here, it would have to know about the distribution over the data for that column and also have many executions of that query to see if "all" executions are using a typical value (sp_executesql might be better) or if the stored density value is a good representation for "all" queries that are passed from the clients. I very much doubt that DTA has this level of sophistication. Basically, I don't know why it advices this. There might be other aspects, like "avoid dynamic SQL" (which whether that holds for this case we could argue in another post), but DTA is about performance, not best practices. &lt;/P&gt;
&lt;P&gt;Bottom line is that these things are not simple and we should be very cautious with "rules of thumbs".&lt;/P&gt;
&lt;P&gt;Here's some TSQL code to demonstrate the differences between 1) and 2). As always, only execute after you read and understood the code!&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:green;"&gt;--Create&amp;nbsp;a&amp;nbsp;copy&amp;nbsp;of&amp;nbsp;the&amp;nbsp;person&amp;nbsp;table &lt;BR&gt;--We&amp;nbsp;will&amp;nbsp;have&amp;nbsp;lots&amp;nbsp;of&amp;nbsp;"Diaz"&amp;nbsp;and&amp;nbsp;very&amp;nbsp;few&amp;nbsp;"Gimmi" &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;OBJECT_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'p'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Person.Person &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;INDEX&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;x&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;dbo.p&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Create&amp;nbsp;lots&amp;nbsp;of&amp;nbsp;Diaz &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;BusinessEntityID&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;+&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;30000&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;PersonType&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;NameStyle&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Title&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FirstName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;MiddleName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'Diaz'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Suffix&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;EmailPromotion&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;AdditionalContactInfo&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Demographics&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;rowguid&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;ModifiedDate &lt;BR&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&amp;nbsp; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Make&amp;nbsp;sure&amp;nbsp;we&amp;nbsp;have&amp;nbsp;up-to-date&amp;nbsp;statistics &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;UPDATE&amp;nbsp;STATISTICS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WITH&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FULLSCAN &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Verify&amp;nbsp;execution&amp;nbsp;plan&amp;nbsp;and&amp;nbsp;I/O&amp;nbsp;cost &lt;BR&gt;--for&amp;nbsp;table&amp;nbsp;scan&amp;nbsp;with&amp;nbsp;low&amp;nbsp;selectivity&amp;nbsp; &lt;BR&gt;--and&amp;nbsp;index&amp;nbsp;seek&amp;nbsp;with&amp;nbsp;high&amp;nbsp;selectivity &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;STATISTICS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;IO&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;ON &lt;BR&gt;&lt;BR&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--20183&amp;nbsp;rows,&amp;nbsp;table&amp;nbsp;scan,&amp;nbsp;7612&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Gimmi' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--1&amp;nbsp;row,&amp;nbsp;index&amp;nbsp;seek,&amp;nbsp;3&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;------------------------------------------------------------ &lt;BR&gt;--sp_execute&amp;nbsp;alternative &lt;BR&gt;------------------------------------------------------------ &lt;BR&gt;&lt;BR&gt;--Table&amp;nbsp;scan&amp;nbsp;will&amp;nbsp;be&amp;nbsp;used&amp;nbsp;for&amp;nbsp;both&amp;nbsp;because&amp;nbsp;of&amp;nbsp;execution&amp;nbsp;plan&amp;nbsp;re-use &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXEC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;sp_executesql&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'SELECT&amp;nbsp;FirstName,&amp;nbsp;LastName,&amp;nbsp;PersonType,&amp;nbsp;Title &lt;BR&gt;FROM&amp;nbsp;p &lt;BR&gt;WHERE&amp;nbsp;LastName&amp;nbsp;=&amp;nbsp;@P1'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'@P1&amp;nbsp;nvarchar(50)'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--20183&amp;nbsp;rows,&amp;nbsp;table&amp;nbsp;scan,&amp;nbsp;7612&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXEC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;sp_executesql&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'SELECT&amp;nbsp;FirstName,&amp;nbsp;LastName,&amp;nbsp;PersonType,&amp;nbsp;Title &lt;BR&gt;FROM&amp;nbsp;p &lt;BR&gt;WHERE&amp;nbsp;LastName&amp;nbsp;=&amp;nbsp;@P1'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'@P1&amp;nbsp;nvarchar(50)'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Gimmi' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--1&amp;nbsp;row,&amp;nbsp;table&amp;nbsp;scan,&amp;nbsp;7612&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;--Other&amp;nbsp;way&amp;nbsp;around &lt;BR&gt;--Index&amp;nbsp;search&amp;nbsp;will&amp;nbsp;be&amp;nbsp;used&amp;nbsp;for&amp;nbsp;both&amp;nbsp;because&amp;nbsp;of&amp;nbsp;execution&amp;nbsp;plan&amp;nbsp;re-use &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXEC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;sp_executesql&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'SELECT&amp;nbsp;FirstName,&amp;nbsp;LastName,&amp;nbsp;PersonType,&amp;nbsp;Title &lt;BR&gt;FROM&amp;nbsp;p &lt;BR&gt;WHERE&amp;nbsp;LastName&amp;nbsp;=&amp;nbsp;@P1'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'@P1&amp;nbsp;nvarchar(50)'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Gimmi' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--1&amp;nbsp;row,&amp;nbsp;index&amp;nbsp;seek,&amp;nbsp;3&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;EXEC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:darkred;"&gt;sp_executesql&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'SELECT&amp;nbsp;FirstName,&amp;nbsp;LastName,&amp;nbsp;PersonType,&amp;nbsp;Title &lt;BR&gt;FROM&amp;nbsp;p &lt;BR&gt;WHERE&amp;nbsp;LastName&amp;nbsp;=&amp;nbsp;@P1'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;, &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;N'@P1&amp;nbsp;nvarchar(50)'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--20183&amp;nbsp;rows,&amp;nbsp;index&amp;nbsp;seek,&amp;nbsp;20291&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;------------------------------------------------------------------ &lt;BR&gt;--Alternative&amp;nbsp;using&amp;nbsp;variable &lt;BR&gt;------------------------------------------------------------------ &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;NVARCHAR&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;50&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Diaz' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FirstName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;PersonType&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Title &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--20183&amp;nbsp;rows,&amp;nbsp;index&amp;nbsp;seek,&amp;nbsp;20291&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FREEPROCCACHE &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DECLARE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;NVARCHAR&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;50&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SET&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'Gimmi' &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;FirstName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;PersonType&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;Title &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@P1 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--1&amp;nbsp;rows,&amp;nbsp;index&amp;nbsp;seek,&amp;nbsp;1&amp;nbsp;pages &lt;BR&gt;&lt;BR&gt;--Same&amp;nbsp;plan&amp;nbsp;even&amp;nbsp;though&amp;nbsp;very&amp;nbsp;different&amp;nbsp;selectivity &lt;BR&gt;--and&amp;nbsp;emptying&amp;nbsp;plan&amp;nbsp;cache&amp;nbsp;in&amp;nbsp;between &lt;BR&gt;&lt;BR&gt;--Estimated&amp;nbsp;33&amp;nbsp;rows&amp;nbsp;for&amp;nbsp;both&amp;nbsp;above. &lt;BR&gt;--See&amp;nbsp;if&amp;nbsp;that&amp;nbsp;is&amp;nbsp;drawn&amp;nbsp;from&amp;nbsp;statistics&amp;nbsp;density? &lt;BR&gt;&lt;BR&gt;--Formula&amp;nbsp;for&amp;nbsp;density:&amp;nbsp;1/#OfUniqueValuesInColumn &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;1.&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;COUNT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DISTINCT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;LastName&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--0.00082918739 &lt;BR&gt;&lt;BR&gt;--Does&amp;nbsp;that&amp;nbsp;match&amp;nbsp;density&amp;nbsp;in&amp;nbsp;index&amp;nbsp;statistics? &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DBCC&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;SHOW_STATISTICS&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'p'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'x'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Yes &lt;BR&gt;&lt;BR&gt;--How&amp;nbsp;many&amp;nbsp;rows&amp;nbsp;in&amp;nbsp;the&amp;nbsp;table? &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;COUNT&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(*)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--39944 &lt;BR&gt;&lt;BR&gt;--So&amp;nbsp;how&amp;nbsp;many&amp;nbsp;rows&amp;nbsp;would&amp;nbsp;we&amp;nbsp;estimate&amp;nbsp;based&amp;nbsp;on&amp;nbsp;density? &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;0.00082918739&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;*&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;39944 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:green;"&gt;--Yep,&amp;nbsp;33&amp;nbsp;rows. &lt;BR&gt;&lt;BR&gt;--I.e,&amp;nbsp;for&amp;nbsp;the&amp;nbsp;variable&amp;nbsp;alternative,&amp;nbsp;SQL&amp;nbsp;Server&amp;nbsp;has&amp;nbsp;no&amp;nbsp; &lt;BR&gt;--knowledge&amp;nbsp;of&amp;nbsp;contents&amp;nbsp;of&amp;nbsp;those&amp;nbsp;variables&amp;nbsp;so&amp;nbsp;it&amp;nbsp;must&amp;nbsp;use&amp;nbsp;density&amp;nbsp;instead. &lt;BR&gt;&lt;BR&gt;--Clean&amp;nbsp;up: &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IF&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;OBJECT_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'p'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;DROP&amp;nbsp;TABLE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;p &lt;BR&gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8644" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Are inserts quicker to heap or clustered tables?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2008/08/14/are-inserts-quicker-to-heap-or-clustered-tables.aspx</link><pubDate>Thu, 14 Aug 2008 12:05:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8372</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>11</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/8372.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=8372</wfw:commentRss><description>&lt;P&gt;Is it quicker and/or lower overhead to insert into a heap vs. a clustered table?&lt;BR&gt;I don't know. So I decided to do a test. Some background information first:&lt;/P&gt;
&lt;P&gt;The test was inspired from a sidebar with Gert-Jan Strik in the open newsgroups. Basically I expressed that a heap doesn't automatically carry lower overhead... just because it is a heap. Now, heaps vs. clustered tables is a huge topic with many aspects. I will not cover anything else here except inserts into a heap vs. a table which is clustered on an ever increasing key. No other indexes. There will be no fragmentation. I do not cover searches, covering etc. Only the pure insert aspect. OK? Good!&lt;/P&gt;
&lt;P&gt;One might think that a heap has lower overhead because it is a ... heap. But hang on for a second and think about what happens when you do an insert:&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Heap:&lt;BR&gt;&lt;/STRONG&gt;SQL Server need to find where the row should go. For this it uses one or more IAM pages for the heap, and it cross references these to one or more PFS pages for the database file(s). IMO, there should be potential for a noticable overhead here. And even more, with many users hammering the same table I can imagine blocking (waits) against the PFS and possibly also IAM pages.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Clustered table:&lt;BR&gt;&lt;/STRONG&gt;Now, this is dead simple. SQL server navigates the clustered index tree and find where the row should go. Since this is an ever increasing index key, each row will go to the end of the table (linked list).&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The result:&lt;BR&gt;&lt;/STRONG&gt;So what is the conclusion? I did several executions of the code at the end of this post, with some variations. Basically there was no or very little difference whith only one user. I.e., no contention to the GAM or PFS pages. This was pretty consistent for below three scenarios:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Insert with subselect. I.e., this inserts lots of rows in the same statement.&lt;/LI&gt;
&lt;LI&gt;Insert in a loop (one insert and row per iteration), many rows in the same transaction.&lt;/LI&gt;
&lt;LI&gt;Insert in a loop, one row per transaction.&amp;nbsp;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Now the difference between 2 and 3 is important. &lt;BR&gt;With many transactions, we incur an overhead of force-log-write-at-commit *for each row*. I.e., much more overhead against the transaction log. And indeed, the timings between 2 and 3 for one of my executions (10000 rows) showed that 2 took on average 650 ms where the same number for 3 was 5600 ms. This is about 9 times longer!!! Now, this was more or less expected, but another important aspect is when we have several users. With many users, we might run into blocking on the PFS and IAM pages. Also, with several users it is meaningless to do it all in one transaction since we will block and essentially single-thread the code anyhow. I.e., the only revelant measure where we run many users is the loop construction where each row is its own transaction (3).&lt;/P&gt;
&lt;P&gt;There was indded a noticeable difference when I executed several inserts in parallell and had each insert in its own transaction (for clustered table vs. heap table). &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Some numbers:&lt;BR&gt;&lt;/STRONG&gt;I did 4 repeated tests&amp;nbsp;and calculated average execution time for inserting 10000 rows for a thread. With 6 parallel thread I had 22 seconds for a clustered table and 29 seconds for a heap table. With 10 threads I had 31 seconds for a clustered table and 42 seconds for a heap table. &lt;/P&gt;
&lt;P&gt;I didn't find performance difference more than a couple of percents for batch inserts, when I single threaded (only one thread pumping inserts), or when I had all inserts in the loop as one transaction.&lt;/P&gt;
&lt;P&gt;Now, I would need lots of more time to run exchaustive tests, but my interpretation is that with many users doing inserts, there is an noticable overhead for the heap vs clustering on a increasing key.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The code:&lt;/STRONG&gt;&lt;BR&gt;Note that for parallell executions, I recommend starting the DoTheInserts procedure using SQLCMD, a BAT file and START. As always, read the code carefully (so you understand it) and execute at your own risk.&lt;/P&gt;
&lt;P&gt;--------------------------------------------&lt;BR&gt;--Create the database etc.&lt;BR&gt;--------------------------------------------&lt;BR&gt;USE master SET NOCOUNT ON&lt;BR&gt;GO&lt;BR&gt;IF DB_ID('TestDb') IS NOT NULL DROP DATABASE TestDb&lt;BR&gt;GO&lt;BR&gt;--Makes files large enough so that inserts don't causes autogrow&lt;BR&gt;CREATE DATABASE TestDb&lt;BR&gt;ON&amp;nbsp; PRIMARY &lt;BR&gt;(NAME = 'TestDb', FILENAME = 'C:\TestDb.mdf', SIZE = 300MB, FILEGROWTH = 50MB)&lt;BR&gt;LOG ON &lt;BR&gt;(NAME = 'TestDb_log', FILENAME = 'C:\TestDb_log.ldf', SIZE = 200MB, FILEGROWTH = 100MB)&lt;BR&gt;GO&lt;BR&gt;--Full recovery to avoid effect of system caused log truncation&lt;BR&gt;ALTER DATABASE TestDb SET RECOVERY FULL&lt;BR&gt;BACKUP DATABASE TestDb TO DISK = 'nul'&lt;BR&gt;USE TestDb&lt;/P&gt;
&lt;P&gt;--Execution time log table&lt;BR&gt;IF OBJECT_ID('TimeLogger') IS NOT NULL DROP TABLE TimeLogger&lt;BR&gt;GO&lt;BR&gt;CREATE TABLE TimeLogger&lt;BR&gt;(&lt;BR&gt;&amp;nbsp;SomeId int identity&lt;BR&gt;,spid int&lt;BR&gt;,TableStructure varchar(10) CHECK (TableStructure IN ('heap', 'clustered'))&lt;BR&gt;,InsertType varchar(20) CHECK (InsertType IN('one statement', 'loop'))&lt;BR&gt;,ExecutionTimeMs int&lt;BR&gt;)&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('RowsToInsert') IS NOT NULL DROP TABLE RowsToInsert&lt;BR&gt;CREATE TABLE RowsToInsert(#rows int)&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;--Support procedures&lt;BR&gt;IF OBJECT_ID('CreateTables') IS NOT NULL DROP PROC CreateTables&lt;BR&gt;GO&lt;BR&gt;CREATE PROC CreateTables AS&lt;BR&gt;IF OBJECT_ID('HeapLoop') IS NOT NULL DROP TABLE HeapLoop&lt;BR&gt;CREATE TABLE HeapLoop(c1 int identity, c2 int DEFAULT 2, c3 datetime DEFAULT GETDATE(), c4 char(200) DEFAULT 'g')&lt;BR&gt;IF OBJECT_ID('ClusteredLoop') IS NOT NULL DROP TABLE ClusteredLoop&lt;BR&gt;CREATE TABLE ClusteredLoop(c1 int identity, c2 int DEFAULT 2, c3 datetime DEFAULT GETDATE(), c4 char(200) DEFAULT 'g')&lt;BR&gt;CREATE CLUSTERED INDEX x ON ClusteredLoop(c1)&lt;BR&gt;IF OBJECT_ID('HeapOneStatement') IS NOT NULL DROP TABLE HeapOneStatement&lt;BR&gt;CREATE TABLE HeapOneStatement(c1 int identity, c2 int DEFAULT 2, c3 datetime DEFAULT GETDATE(), c4 char(200) DEFAULT 'g')&lt;BR&gt;IF OBJECT_ID('ClusteredOneStatement') IS NOT NULL DROP TABLE ClusteredOneStatement&lt;BR&gt;CREATE TABLE ClusteredOneStatement(c1 int identity, c2 int DEFAULT 2, c3 datetime DEFAULT GETDATE(), c4 char(200) DEFAULT 'g')&lt;BR&gt;CREATE CLUSTERED INDEX x ON ClusteredOneStatement(c1)&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('TruncateTables') IS NOT NULL DROP PROC TruncateTables&lt;BR&gt;GO&lt;BR&gt;CREATE PROC TruncateTables AS&lt;BR&gt;TRUNCATE TABLE HeapLoop&lt;BR&gt;TRUNCATE TABLE ClusteredLoop&lt;BR&gt;TRUNCATE TABLE HeapOneStatement&lt;BR&gt;TRUNCATE TABLE ClusteredOneStatement&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('DoBefore') IS NOT NULL DROP PROC DoBefore&lt;BR&gt;GO&lt;BR&gt;CREATE PROC DoBefore AS&lt;BR&gt;BACKUP LOG TestDb TO DISK = 'nul'&lt;BR&gt;CHECKPOINT&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('iHeapLoop') IS NOT NULL DROP PROC iHeapLoop&lt;BR&gt;GO&lt;BR&gt;CREATE PROC iHeapLoop @rows int AS&lt;BR&gt;DECLARE @i int = 1&lt;BR&gt;WHILE @i &amp;lt;= @rows&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;INSERT INTO HeapLoop (c2) VALUES(2)&lt;BR&gt;&amp;nbsp;SET @i = @i + 1&lt;BR&gt;END&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('iClusteredLoop') IS NOT NULL DROP PROC iClusteredLoop&lt;BR&gt;GO&lt;BR&gt;CREATE PROC iClusteredLoop @rows int AS&lt;BR&gt;DECLARE @i int = 1&lt;BR&gt;WHILE @i &amp;lt;= @rows&lt;BR&gt;BEGIN&lt;BR&gt;&amp;nbsp;INSERT INTO ClusteredLoop (c2) VALUES(2)&lt;BR&gt;&amp;nbsp;SET @i = @i + 1&lt;BR&gt;END&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('iHeapOneStatement') IS NOT NULL DROP PROC iHeapOneStatement&lt;BR&gt;GO&lt;BR&gt;CREATE PROC iHeapOneStatement @rows int AS&lt;BR&gt;INSERT INTO HeapOneStatement (c2)&lt;BR&gt;SELECT TOP(@rows) 2 FROM syscolumns a CROSS JOIN syscolumns b&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;IF OBJECT_ID('iClusteredOneStatement') IS NOT NULL DROP PROC iClusteredOneStatement&lt;BR&gt;GO&lt;BR&gt;CREATE PROC iClusteredOneStatement @rows int AS &lt;BR&gt;INSERT INTO ClusteredOneStatement (c2)&lt;BR&gt;SELECT TOP(@rows) 2 FROM syscolumns a CROSS JOIN syscolumns b&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;--Proc to do the inserts&lt;BR&gt;IF OBJECT_ID('DoTheInserts') IS NOT NULL DROP PROC DoTheInserts&lt;BR&gt;GO&lt;BR&gt;CREATE PROC DoTheInserts&lt;BR&gt;AS&lt;BR&gt;DECLARE @dt datetime, @NumberOfRowsToInsert int&lt;BR&gt;SET @NumberOfRowsToInsert = (SELECT #rows FROM RowsToInsert)&lt;BR&gt;EXEC DoBefore --Batch allocation, heap:&lt;BR&gt;SET @dt = GETDATE()&lt;BR&gt;EXEC iHeapOneStatement @rows = @NumberOfRowsToInsert&lt;BR&gt;INSERT INTO TimeLogger (spid, TableStructure, InsertType, ExecutionTimeMs)&lt;BR&gt;VALUES(@@SPID, 'heap', 'one statement', DATEDIFF(ms, @dt, GETDATE()))&lt;/P&gt;
&lt;P&gt;EXEC DoBefore --Batch allocation, clustered:&lt;BR&gt;SET @dt = GETDATE()&lt;BR&gt;EXEC iClusteredOneStatement @rows = @NumberOfRowsToInsert&lt;BR&gt;INSERT INTO TimeLogger (spid, TableStructure, InsertType, ExecutionTimeMs)&lt;BR&gt;VALUES(@@SPID, 'clustered', 'one statement', DATEDIFF(ms, @dt, GETDATE()))&lt;/P&gt;
&lt;P&gt;EXEC DoBefore --Single allocations, heap:&lt;BR&gt;SET @dt = GETDATE()&lt;BR&gt;--BEGIN TRAN&lt;BR&gt;EXEC iHeapLoop @rows = @NumberOfRowsToInsert&lt;BR&gt;--COMMIT&lt;BR&gt;INSERT INTO TimeLogger (spid, TableStructure, InsertType, ExecutionTimeMs)&lt;BR&gt;VALUES(@@SPID, 'heap', 'loop', DATEDIFF(ms, @dt, GETDATE()))&lt;/P&gt;
&lt;P&gt;EXEC DoBefore --Single allocations, clustered&lt;BR&gt;SET @dt = GETDATE()&lt;BR&gt;--BEGIN TRAN&lt;BR&gt;EXEC iClusteredLoop @rows = @NumberOfRowsToInsert&lt;BR&gt;--COMMIT&lt;BR&gt;INSERT INTO TimeLogger (spid, TableStructure, InsertType, ExecutionTimeMs)&lt;BR&gt;VALUES(@@SPID, 'clustered', 'loop', DATEDIFF(ms, @dt, GETDATE()))&lt;BR&gt;GO&lt;/P&gt;
&lt;P&gt;--Run the tests&lt;BR&gt;EXEC CreateTables&lt;BR&gt;TRUNCATE TABLE TimeLogger&lt;BR&gt;TRUNCATE TABLE RowsToInsert INSERT INTO RowsToInsert VALUES(10000)&lt;/P&gt;
&lt;P&gt;--&amp;lt;Below can be executed over several connections&amp;gt;&lt;BR&gt;EXEC DoTheInserts&lt;BR&gt;EXEC DoTheInserts&lt;BR&gt;EXEC DoTheInserts&lt;BR&gt;EXEC DoTheInserts&lt;BR&gt;--&amp;lt;/Below can be executed over several connections&amp;gt;&lt;/P&gt;
&lt;P&gt;--How did we do?&lt;BR&gt;SELECT COUNT(*) AS NumberOfExecutions, TableStructure, InsertType, AVG(ExecutionTimeMs) AS AvgMs&lt;BR&gt;FROM TimeLogger WITH(NOLOCK)&lt;BR&gt;GROUP BY TableStructure, InsertType&lt;BR&gt;ORDER BY InsertType, TableStructure&lt;/P&gt;
&lt;P&gt;--Verify that no fragmentation&lt;BR&gt;SELECT &lt;BR&gt;&amp;nbsp;OBJECT_NAME(OBJECT_ID) AS objName&lt;BR&gt;,index_type_desc&lt;BR&gt;,avg_fragmentation_in_percent AS frag&lt;BR&gt;,page_count AS #pages&lt;BR&gt;,record_count&lt;BR&gt;FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED')&lt;BR&gt;WHERE OBJECT_NAME(OBJECT_ID) &amp;lt;&amp;gt; 'TimeLogger' AND index_level = 0&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8372" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Yet some more fixes for sp_indexinfo...</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2008/07/09/yet-some-more-fixes-for-sp-indexinfo.aspx</link><pubDate>Wed, 09 Jul 2008 08:03:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7739</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>4</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/7739.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=7739</wfw:commentRss><description>&lt;P&gt;I got some more feedback (see yesterday's blog post on this) which I now incorporated into sp_indexinfo. See change log at bottom of the article for details.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp"&gt;http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp&lt;/A&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7739" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>New version of sp_indexinfo</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2008/07/08/new-version-of-sp-indexinfo.aspx</link><pubDate>Tue, 08 Jul 2008 07:58:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7715</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>5</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/7715.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=7715</wfw:commentRss><description>&lt;P&gt;(See my &lt;A class="" title="initial blog post" href="http://sqlblog.com/blogs/tibor_karaszi/archive/2008/07/07/fed-up-with-hunting-physical-index-details.aspx"&gt;initial blog post&lt;/A&gt; for&amp;nbsp;general information about this proc.)&lt;/P&gt;
&lt;P&gt;I just updated sp_indexinfo a bit:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;I added the schema name as a new column in the output of the first resultset.&lt;/LI&gt;
&lt;LI&gt;I added an optional second resultset with missing index information. This information is obviously&amp;nbsp;drawn from the missing index dynamic management views. I'm not sure I generated the CREATE INDEX statment properly (the equality and inequality columns) since I didn't have much missing index entries to play with at the moment. All tests and replies are much welcome ("work fine" - "doesn't work" - "doesn't work because of..." - "change aaa to bbb" etc.).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I also updated the web site with some tips on creating a view in the databases where &lt;STRONG&gt;you want to work a lot&lt;/STRONG&gt; so you can select from this view, aggregate etc. I will try to as much as possible stick with less procedural code and more set-based code. My aim is to have perhaps only two SELECT statements in the proc, so we can just take a SELECT statement, create a view or function inside your database and work with it from there. So, for instance, I will probably not add support for specify 'schemaname.tablename' for the first parameter as that will probably require some procedural parsing code (as seen in sp_helpindex). There's a trade-off between all the nice things you can complement using procedural code and having all in one or a few SELECT statments and being able to simply creating a view or table function from those. &lt;/P&gt;
&lt;P&gt;One possible enhancement is to add fragmentation information. For this I will need to perform some type of join or subquery against sys.dm_db_index_physical_stats. My concern here is the cases where you &lt;STRONG&gt;don't&lt;/STRONG&gt; want this information (because&amp;nbsp;of cost for large tables/databases). Ideally I don't want two versions of the query (see above paragraph) but I also don't want to pay the penalty in cases where we don't want this info. Possibly this is doable using some correlated subquery as a column together with CASE, but this is only in my mind yet. Suggestions and thoughts are welcome.&lt;/P&gt;
&lt;P&gt;You find the proc at: &lt;A href="http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp"&gt;http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp&lt;/A&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7715" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Fed up with hunting physical index details?</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2008/07/07/fed-up-with-hunting-physical-index-details.aspx</link><pubDate>Mon, 07 Jul 2008 12:17:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7687</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>7</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/7687.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=7687</wfw:commentRss><description>&lt;P&gt;I am. I find myself endlessly hunting for index information when working against the various SQL Servers I come in contact with. And, sure, the information is there. You just need to go and get it. This generally means that I start with sp_helpindex. Then some SELECT from sys.indexes. Then some more against sys.partitions and sys.allocation units (we want space usage stats as well). And perhaps general usage stats (sys.dm_index_usage_stats). (I sometimes might even use the GUI (SSMS) reports and index dialog - but you might already know that I'm not much of a GUI person.)&lt;/P&gt;
&lt;P&gt;The good news with all this is that I learn to use these catalog and dynamic management views. Bad news is that it is kind of ... boring to do the same thing again and again. &lt;/P&gt;
&lt;P&gt;This is why wrote sp_indexinfo. You might have your own index information procedures (which you wrote yourself or found on the Internet). If not, you are welcome to use this one. I aim to improve it over time, so suggestions are welcome. Possible improvements include:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Make it a function. Functions are nice since we can order the results, aggregate, and basically do whatever we want to when we SELECT from the function. But for this I need to find out how we install a user-defined global system function - there's no supported way to do this. I'm not sure I want to go there...&lt;/LI&gt;
&lt;LI&gt;Reurn missing index information as well. For this we probably want two resultsets, and only return missing index information when we targeted *one* table (no wildcards). If we do this, then function is out since a function can only return *one* result set.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;If you care to give it a spin, please let me know. I just wrote the procedure, so I haven't tested it much yet. If you do find bugs, please leave a comment and I will incorporate into the source (let me know if you want to be acknowledged). Any comments are welcome.&lt;/P&gt;
&lt;P&gt;You find the proc at: &lt;A href="http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp"&gt;http://www.karaszi.com/SQLServer/util_sp_indexinfo.asp&lt;/A&gt;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7687" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/Performance/default.aspx">Performance</category><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Find table and index name for fragmented indexes</title><link>http://sqlblog.com/blogs/tibor_karaszi/archive/2007/11/11/find-table-and-index-name-for-fragmented-indexes.aspx</link><pubDate>Sun, 11 Nov 2007 19:53:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:3285</guid><dc:creator>TiborKaraszi</dc:creator><slash:comments>14</slash:comments><comments>http://sqlblog.com/blogs/tibor_karaszi/comments/3285.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/tibor_karaszi/commentrss.aspx?PostID=3285</wfw:commentRss><description>&lt;P&gt;Got this question from a newsgroup today. The answer is pretty simple, just use the dynamic management view sys.dm_db_index_physical_stats. I'm posting this here mostly so I have somewhere to refer to when asked this question... &lt;/P&gt;
&lt;P&gt;I prefer to have a helper function to get the index name:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;dbo.index_name&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@object_id&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;int&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@index_id&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;int&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;RETURNS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;sysname &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;AS &lt;BR&gt;BEGIN &lt;BR&gt;&amp;nbsp;&amp;nbsp;RETURN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;name&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;sys.indexes&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;object_id&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@object_id&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;and&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;index_id&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;=&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:#434343;"&gt;@index_id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;END&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;; &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;GO &lt;/SPAN&gt;&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;And then a simple query:&lt;/P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:blue;"&gt;SELECT&amp;nbsp; &lt;BR&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;OBJECT_NAME&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;object_id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;AS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;tblName &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;dbo.index_name&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;object_id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;index_id&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;AS&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;ixName &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;avg_fragmentation_in_percent &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;FROM&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;sys.dm_db_index_physical_stats&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:magenta;"&gt;DB_ID&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(),&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;NULL,&amp;nbsp;NULL) &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;WHERE&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;avg_fragmentation_in_percent&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;&amp;gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;20 &lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;AND&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:black;"&gt;index_type_desc&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:blue;"&gt;IN&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;(&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'CLUSTERED&amp;nbsp;INDEX'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="COLOR:red;"&gt;'NONCLUSTERED&amp;nbsp;INDEX'&lt;/SPAN&gt;&lt;SPAN style="COLOR:gray;"&gt;)&lt;/SPAN&gt;&lt;/CODE&gt; 
&lt;P&gt;Then you just adjust the search clause to your liking. One hint is to exclude nindexes with few pages (the page_count column).&lt;/P&gt;
&lt;P&gt;&lt;CODE style="FONT-SIZE:12px;"&gt;&lt;SPAN style="COLOR:black;"&gt;&amp;nbsp;&lt;/P&gt;&lt;/SPAN&gt;&lt;/CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=3285" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/tibor_karaszi/archive/tags/indexes/default.aspx">indexes</category></item></channel></rss>