<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www2.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>Kalen Delaney : fragmentation</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/fragmentation/default.aspx</link><description>Tags: fragmentation</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Geek City: Fragmentation and Forwarded Records in a Heap</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2009/11/11/fragmentation-and-forwarded-records-in-a-heap.aspx</link><pubDate>Thu, 12 Nov 2009 01:31:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:18762</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>10</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/18762.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=18762</wfw:commentRss><description>I know it's been a while since I had a technical post, and I've got 3 of them started and saved as drafts. I keep waiting for spare time. Now that PASS is over, and I've crawled partway out from under the TO-DO pile that accumulated while I was preparing...(&lt;a href="http://www2.sqlblog.com/blogs/kalen_delaney/archive/2009/11/11/fragmentation-and-forwarded-records-in-a-heap.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=18762" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/forwarding+pointers/default.aspx">forwarding pointers</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/fragmentation/default.aspx">fragmentation</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/internals/default.aspx">internals</category></item><item><title>Geek City: Fragmentation Internals</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2008/03/06/fragmentation-internals.aspx</link><pubDate>Thu, 06 Mar 2008 21:42:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:5487</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>1</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/5487.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=5487</wfw:commentRss><description>&lt;P&gt;Yet another fragmentation post, to answer a question asked in response to &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/02/28/fragmentation-revisited.aspx" target=_blank&gt;a previous answer&lt;/A&gt;....&lt;/P&gt;
&lt;P&gt;SQL_Girl is still confused about DETAILED vs LIMITED, and I don't blame her. She reported that the BOL says:&amp;nbsp; "The nonleaf levels of indexes are only processed when mode = DETAILED. "&amp;nbsp; But I had said: "The second misunderstanding involves what LIMITED means. LIMITED does not ONLY show the leaf level, in fact, just the opposite. LIMITED does not evaluate pages at the leaf level at all." &lt;/P&gt;
&lt;P&gt;So my answer actual was partly incorrect, and also partly just a confusion about what "processed" or "evaluated" means.&lt;/P&gt;
&lt;P&gt;I was incorrect in implying that LIMITED gave you &lt;STRONG&gt;everything&lt;/STRONG&gt; but the leaf. It only &lt;STRONG&gt;displays&lt;/STRONG&gt; information for the leaf level. Thanks to SQL_Girl for keeping me honest here.&lt;/P&gt;
&lt;P&gt;However, what exactly does "processed" mean? Most of the referenced post was about logical fragmentation as reported in the column &lt;EM&gt;avg_fragmentation_in_percent&lt;/EM&gt;. Logical fragmentation is a measure of how 'out of order' the pages are. How can SQL Server determine whether the pages are out of order or not?&lt;/P&gt;
&lt;P&gt;Below is a graphic that I use in my classes when discussing index structures. In the graphic, the leaf level has no logical fragmentation because the logical order, from values 1 to 80,000 is the same as the physical page numbers, 1151 to 2150. SQL Server can determine this without actually touching the leaf level at all. This information is available at Level 1. The index pages at level 1 have a pointer to every single page at the leaf level. Each index row at level 1 includes the first key value on a page at level 0, and then the file number and page number which start with that key value. When determining the value for &lt;EM&gt;avg_fragmentation_in_percent&lt;/EM&gt;, SQL Server can just look at the index pages at level 1 and see the page numbers in order (all on file 1): 1151, 1152, 1153....2150. So it reports that at level 0 there is&amp;nbsp;a 0 value for &amp;nbsp;&lt;EM&gt;avg_fragmentation_in_percent (&lt;/EM&gt;i.e. NO fragmentation&lt;EM&gt;)&lt;/EM&gt;. If there was fragmentation, SQL Server could determine that by looking at the level above the leaf. For LIMITED, that is basically all SQL Server does...it looks at the level above the leaf (level 1)&amp;nbsp;to report whatever it can about the leaf level (level 0).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityFragmenationInternals_B89B/image_8.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH:0px;BORDER-LEFT-WIDTH:0px;BORDER-BOTTOM-WIDTH:0px;BORDER-RIGHT-WIDTH:0px;" height=203 alt=image src="http://sqlblog.com/blogs/kalen_delaney/WindowsLiveWriter/GeekCityFragmenationInternals_B89B/image_thumb_3.png" width=311 border=0&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;When I mentioned the term "processed" I was talking about all the other work that SQL Server does in DETAILED mode. It figures out the values for&amp;nbsp; min, max and avg record size, ghost and forwarded record counts, and the value for &lt;EM&gt;avg_page_space_used_in_percent&lt;/EM&gt;. It cannot get these values without actually examining every single page at the leaf level and in LIMITED mode it does not do that. It stays at the level above the leaf and does what it can from there.&lt;/P&gt;
&lt;P&gt;So, to summarize:&lt;/P&gt;
&lt;P&gt;In LIMITED mode, SQL Server scans only level 1 and reports the logical fragmentation of level 0.&lt;/P&gt;
&lt;P&gt;In DETAILED mode, SQL Server scans every level, and reports on all kinds of stuff. &lt;/P&gt;
&lt;P&gt;This is still just a summary, because there is all kinds of other information, such as&amp;nbsp;when you have LOB and row-overflow data, etc. But that's for another time.&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff size=4&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=5487" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/fragmentation/default.aspx">fragmentation</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/indexes/default.aspx">indexes</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/storage/default.aspx">storage</category></item><item><title>Did You Know? Fragmentation, revisited....</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2008/02/28/fragmentation-revisited.aspx</link><pubDate>Fri, 29 Feb 2008 01:00:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:5345</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>7</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/5345.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=5345</wfw:commentRss><description>&lt;P&gt;&lt;FONT size=1&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;A couple of questions arrived regarding my earlier post about &lt;A href="http://sqlblog.com/blogs/kalen_delaney/archive/2008/01/17/fragmentation-on-the-system-tables.aspx" target=_blank&gt;fragmentation on the system tables&lt;/A&gt;, and since the questions really don't have anything to do with system tables, I felt they deserved a new post.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;1) Using the DETAILED option includes the non-zero index-levels as well (non-leaf pages).&amp;nbsp; According to many source, this should also be actioned, seeing that this indicates "logical" fragmentation (meaning that the leaf pages are not in the order of the non-leaf keys any more).&amp;nbsp; I cannot find anything conclusive on this.&amp;nbsp; Where as the index level=0 occurrences, indicates extent fragmentation.&amp;nbsp; We are using this dmv, to check fragmentation-levels first, and based on that, do the necessary re-index/reorg.&amp;nbsp; Currently we are using the LIMITED option (which only shows leaf-level), but we seem to be missing indexes that needs to be re-indexed/re-orged.&lt;/STRONG&gt;&lt;/EM&gt; 
&lt;P&gt;There are two&amp;nbsp; misunderstandings reflected in this question. Although there are several types of fragmentation, the value in the avg_fragmentation_in_percent represents only logical fragmentation, in any level of any index. Yes, there can be logical fragmentation in the upper levels, which may need to be addressed in some very large tables. Extent fragmentation is only reported for heaps, and once you have a clustered index, the table itself is just the leaf level of the index.&amp;nbsp; So basically, there is no difference between the meaning of the avg_fragmentation_in_percent value no matter what level you are at. However, fragmentation is really only an issue if there are LOTS of pages. I usually say that if there are less than 100 pages, you should never worry about fragmentation. However, this this whitepaper suggests that a better cutoff would actually be 1000 pages: 
&lt;P&gt;&lt;A href="http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/ss2kidbp.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/ss2kidbp.mspx&lt;/A&gt; 
&lt;P&gt;It would need to be a very big table to have upper levels of indexes with more than 1000 pages, and the sys.dm_db_index_physical_stats view does show you the number of pages at each level. 
&lt;P&gt;The second misunderstanding involves what LIMITED means. LIMITED does not ONLY show leaf level, in fact, just the opposite. LIMITED does not evaluate pages at the leaf level at all. It can still determine the logical fragmentation because of the pointers in the upper levels, but LIMITED will return no values that require actually examining the leaf level rows. This includes values like min, max and avg record size, ghost and forwarded records counts, and the value for avg_page_space_used_in_percent. If you just want to see logical fragmentation to know if defrag or reorg might help, LIMITED should be fine. 
&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;2)&amp;nbsp;&amp;nbsp; Secondly, the stats that this function return, does not seem to be reliable.&amp;nbsp; I ran the function prior to an ALTER…. REBUILD, and then again thereafter.&amp;nbsp; There were hardly any differences in the stats.&amp;nbsp; Is it now a case of the stats being unreliable, or the REBUILD not being effective?&lt;/STRONG&gt;&lt;/EM&gt; 
&lt;P&gt;REBUILD doesn't seem to make a difference in the avg_fragmentation_in_percent value is when there are too few pages in the table. &lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=5345" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/DMVs/default.aspx">DMVs</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/fragmentation/default.aspx">fragmentation</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/indexes/default.aspx">indexes</category></item><item><title>Geek City: Fragmentation on the System Tables</title><link>http://www2.sqlblog.com/blogs/kalen_delaney/archive/2008/01/17/fragmentation-on-the-system-tables.aspx</link><pubDate>Fri, 18 Jan 2008 01:05:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:4576</guid><dc:creator>Kalen Delaney</dc:creator><slash:comments>4</slash:comments><comments>http://www2.sqlblog.com/blogs/kalen_delaney/comments/4576.aspx</comments><wfw:commentRss>http://www2.sqlblog.com/blogs/kalen_delaney/commentrss.aspx?PostID=4576</wfw:commentRss><description>&lt;P&gt;It's my first post of the new year. I hope it's starting out well for all of you! New year, but sometimes the same old questions. I got another email asking about defragging the system tables. It seems to be in the Hit Parade of FAQs. &lt;/P&gt;
&lt;P&gt;First of all, WHY do you think you would need to defrag a system table? Fragmentation is only a problem when you are performing an in-order scan on a table of more than 100 pages or so, and how often do you do that to a system table that is that big? Rarely, I would assume, but let me know if you have seen an actual need for defragging a system table.&lt;/P&gt;
&lt;P&gt;In SQL Server 2000, you can actually use a system table as a parameter to DBCC SHOWCONTIG to see the fragmentation values. One of my readers reported that he tried running a DBCC INDEXDEFRAG on SQL 2000 system tables and while sometimes it worked, sometimes it corrupted the table! It doesn't sound worth it to me. &lt;/P&gt;
&lt;P&gt;And now, with SQL Server 2005 there is no way to see the fragmentation on the system tables. What about using the new Dynamic Management Object sys.dm_db_index_physical_stats? It requires an object_id as a parameter, and if you select from the metadata view sys.all_objects you can see the object_id for the real system tables, even if you're not using the DAC. Try this:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" color=#004080&gt;select * from sys.all_objects&lt;BR&gt;where type = 'S'&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;You should see all the system tables in your current database, and their object IDs. So you could try passing the id to the management view. Here I'll try it for &lt;EM&gt;syshobts&lt;/EM&gt;, which has an ID of 15:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#000080&gt;&lt;FONT face="Courier New"&gt;select * from &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT face="Courier New"&gt;sys.dm_db_index_physical_stats(1, 15, null, null, 'detailed')&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;No results are returned. If I replace the 15 with null, to indicate I want all objects, I do not see any objects with IDs less than 100, which means there are no system objects reported.&lt;/P&gt;
&lt;P&gt;I did notice one interesting behavior while playing around with this concept. If I use the old DBCC SHOWCONTIG and try to get a report for a system table, this command gives me an error:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new" color=#004080&gt;dbcc showcontig ('syshobts')&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="courier new" color=#ff0000&gt;Msg 2501, Level 16, State 45, Line 1&lt;BR&gt;Cannot find a table or object with the name "syshobts". Check the system catalog.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;However, if I qualify the table name with the schema name, something different happens.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new" color=#004080&gt;dbcc showcontig ('sys.syshobts')&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This time, I don't get an error. I don't get a fragmentation report, but I don't get an error. I just get the message that DBCC execution completed. So it's obvious that there is a difference here. If I then intentionally misspell the object name&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new" color=#004080&gt;dbcc showcontig ('sys.syshobbits')&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;now I get the error that SQL Server cannot find the object. So it seems that in SQL Server 2005, DBCC SHOWCONTIG is deliberately filtering out the real system tables, and it was by design to not return fragmentation information. So even if you could run defrag on your system tables, you could never know what impact you had!&lt;/P&gt;
&lt;P&gt;I think there's better ways to spend our time.&lt;/P&gt;
&lt;P&gt;Have fun!&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff00ff&gt;~Kalen&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://www2.sqlblog.com/aggbug.aspx?PostID=4576" width="1" height="1"&gt;</description><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/DMVs/default.aspx">DMVs</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/fragmentation/default.aspx">fragmentation</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/internals/default.aspx">internals</category><category domain="http://www2.sqlblog.com/blogs/kalen_delaney/archive/tags/metadata/default.aspx">metadata</category></item></channel></rss>