<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SQL Fool &#187; Internals</title>
	<atom:link href="http://sqlfool.com/category/internals/feed/" rel="self" type="application/rss+xml" />
	<link>http://sqlfool.com</link>
	<description>Self-Professed SQL Scripting Junkie!</description>
	<lastBuildDate>Wed, 02 May 2012 21:25:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Effective Clustered Indexing</title>
		<link>http://sqlfool.com/2011/01/effective-clustered-indexing/</link>
		<comments>http://sqlfool.com/2011/01/effective-clustered-indexing/#comments</comments>
		<pubDate>Fri, 07 Jan 2011 15:03:49 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[article]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[clustered indexes]]></category>
		<category><![CDATA[clustering]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[redgate]]></category>
		<category><![CDATA[simple-talk]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=1467</guid>
		<description><![CDATA[My first Simple-Talk article was published yesterday! I&#8217;m pretty excited about it and wanted to share the link. In the article, I give an overview of how clustered and nonclustered indexes work, and I demonstrate why clustered index best practices &#8212; narrow, unique, static, and ever-increasing &#8212; are important design considerations. You can find the [...]]]></description>
			<content:encoded><![CDATA[<p>My first <a href="http://www.simple-talk.com/" target="_blank">Simple-Talk</a> article was published yesterday!  I&#8217;m pretty excited about it and wanted to share the link.  In the article, I give an overview of how clustered and nonclustered indexes work, and I demonstrate why clustered index best practices &#8212; narrow, unique, static, and ever-increasing &#8212; are important design considerations.</p>
<p>You can find the article on Simple-Talk&#8217;s website at:<br />
<a href="http://www.simple-talk.com/sql/learn-sql-server/effective-clustered-indexes/" target="_blank">http://www.simple-talk.com/sql/learn-sql-server/effective-clustered-indexes/</a></p>
<p>Please let me know your thoughts!  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2011/01/effective-clustered-indexing/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Index Interrogation for SQL Server 2008</title>
		<link>http://sqlfool.com/2010/06/index-interrogation-for-sql-server-2008/</link>
		<comments>http://sqlfool.com/2010/06/index-interrogation-for-sql-server-2008/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 19:55:17 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[SQL 2008]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[T-SQL Scripts]]></category>
		<category><![CDATA[indexes]]></category>
		<category><![CDATA[partitioning]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[TSQL]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=1344</guid>
		<description><![CDATA[I had previously posted an index interrogation script for SQL Server 2005. I&#8217;ve updated that script for 2008; namely, it includes filtered index definitions. For anyone interested: Declare @objectID int = Object_ID&#40;'Sales.SalesOrderHeader'&#41;; &#160; With indexCTE&#40;partition_scheme_name , partition_function_name , data_space_id&#41; As &#40; Select sps.name , spf.name , sps.data_space_id From sys.partition_schemes As sps Join sys.partition_functions As spf [...]]]></description>
			<content:encoded><![CDATA[<p>I had previously posted an index interrogation script for SQL Server 2005.  I&#8217;ve updated that script for 2008; namely, it includes filtered index definitions.  For anyone interested:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Declare</span> @objectID <span style="color: #0000FF;">int</span> <span style="color: #808080;">=</span> <span style="color: #FF00FF;">Object_ID</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'Sales.SalesOrderHeader'</span><span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">With</span> indexCTE<span style="color: #808080;">&#40;</span>partition_scheme_name
            , partition_function_name
            , data_space_id<span style="color: #808080;">&#41;</span>
<span style="color: #0000FF;">As</span> <span style="color: #808080;">&#40;</span>
    <span style="color: #0000FF;">Select</span> sps.<span style="color: #202020;">name</span>
        , spf.<span style="color: #202020;">name</span>
        , sps.<span style="color: #202020;">data_space_id</span>
    <span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">partition_schemes</span> <span style="color: #0000FF;">As</span> sps
    Join sys.<span style="color: #202020;">partition_functions</span> <span style="color: #0000FF;">As</span> spf
        <span style="color: #0000FF;">On</span> sps.<span style="color: #202020;">function_id</span> <span style="color: #808080;">=</span> spf.<span style="color: #202020;">function_id</span>
<span style="color: #808080;">&#41;</span>
&nbsp;
<span style="color: #0000FF;">Select</span> st.<span style="color: #202020;">name</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'table_name'</span>
    , IsNull<span style="color: #808080;">&#40;</span>ix.<span style="color: #202020;">name</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'index_name'</span>
    , ix.<span style="color: #FF00FF;">object_id</span>
    , ix.<span style="color: #202020;">index_id</span>
	, <span style="color: #0000FF;">Cast</span><span style="color: #808080;">&#40;</span>
        <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span> <span style="color: #000;">1</span> 
                <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">'clustered'</span> 
            <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span><span style="color: #000;">0</span>
                <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">'heap'</span>
            <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">'nonclustered'</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">ignore_dup_key</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', ignore duplicate keys'</span> 
                <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">is_unique</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', unique'</span> 
                <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">is_primary_key</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', primary key'</span> <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span> <span style="color: #0000FF;">As</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">210</span><span style="color: #808080;">&#41;</span>
        <span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'index_description'</span>
    , IsNull<span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span> <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span> <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span>
        <span style="color: #808080;">&#40;</span>   
            <span style="color: #0000FF;">Select</span> c.<span style="color: #202020;">name</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'columnName'</span>
            <span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">index_columns</span> <span style="color: #0000FF;">As</span> sic
            Join sys.<span style="color: #202020;">columns</span> <span style="color: #0000FF;">As</span> c 
                <span style="color: #0000FF;">On</span> c.<span style="color: #202020;">column_id</span> <span style="color: #808080;">=</span> sic.<span style="color: #202020;">column_id</span> 
                And c.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> sic.<span style="color: #FF00FF;">object_id</span>
            <span style="color: #0000FF;">Where</span> sic.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> ix.<span style="color: #FF00FF;">object_id</span>
                And sic.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span> ix.<span style="color: #202020;">index_id</span>
                And is_included_column <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
            <span style="color: #0000FF;">Order</span> <span style="color: #0000FF;">By</span> sic.<span style="color: #202020;">index_column_id</span>
            <span style="color: #0000FF;">For</span> XML Raw<span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&quot;/&gt;&lt;row columnName=&quot;'</span>, <span style="color: #FF0000;">', '</span><span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&lt;row columnName=&quot;'</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&quot;/&gt;'</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
        <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'indexed_columns'</span>
    , IsNull<span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span> <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span> <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span>
        <span style="color: #808080;">&#40;</span>   
            <span style="color: #0000FF;">Select</span> c.<span style="color: #202020;">name</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'columnName'</span>
            <span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">index_columns</span> <span style="color: #0000FF;">As</span> sic
            Join sys.<span style="color: #202020;">columns</span> <span style="color: #0000FF;">As</span> c 
                <span style="color: #0000FF;">On</span> c.<span style="color: #202020;">column_id</span> <span style="color: #808080;">=</span> sic.<span style="color: #202020;">column_id</span> 
                And c.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> sic.<span style="color: #FF00FF;">object_id</span>
            <span style="color: #0000FF;">Where</span> sic.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> ix.<span style="color: #FF00FF;">object_id</span>
                And sic.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span> ix.<span style="color: #202020;">index_id</span>
                And is_included_column <span style="color: #808080;">=</span> <span style="color: #000;">1</span>
            <span style="color: #0000FF;">Order</span> <span style="color: #0000FF;">By</span> sic.<span style="color: #202020;">index_column_id</span>
            <span style="color: #0000FF;">For</span> XML Raw<span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&quot;/&gt;&lt;row columnName=&quot;'</span>, <span style="color: #FF0000;">', '</span><span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&lt;row columnName=&quot;'</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
            , <span style="color: #FF0000;">'&quot;/&gt;'</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
        <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'included_columns'</span>
    , ix.<span style="color: #202020;">filter_definition</span>
    , IsNull<span style="color: #808080;">&#40;</span>cte.<span style="color: #202020;">partition_scheme_name</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'partition_scheme_name'</span>
    , <span style="color: #FF00FF;">Count</span><span style="color: #808080;">&#40;</span>partition_number<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'partition_count'</span>
    , <span style="color: #FF00FF;">Sum</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">rows</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'row_count'</span>
<span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">indexes</span> <span style="color: #0000FF;">As</span> ix
Join sys.<span style="color: #202020;">partitions</span> <span style="color: #0000FF;">As</span> sp
    <span style="color: #0000FF;">On</span> ix.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> sp.<span style="color: #FF00FF;">object_id</span>
    And ix.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span> sp.<span style="color: #202020;">index_id</span>
Join sys.<span style="color: #202020;">tables</span> <span style="color: #0000FF;">As</span> st
    <span style="color: #0000FF;">On</span> ix.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> st.<span style="color: #FF00FF;">object_id</span>
<span style="color: #0000FF;">Left</span> Join indexCTE <span style="color: #0000FF;">As</span> cte
    <span style="color: #0000FF;">On</span> ix.<span style="color: #202020;">data_space_id</span> <span style="color: #808080;">=</span> cte.<span style="color: #202020;">data_space_id</span>
<span style="color: #0000FF;">Where</span> ix.<span style="color: #FF00FF;">object_id</span> <span style="color: #808080;">=</span> IsNull<span style="color: #808080;">&#40;</span>@objectID, ix.<span style="color: #FF00FF;">object_id</span><span style="color: #808080;">&#41;</span>
<span style="color: #0000FF;">Group</span> <span style="color: #0000FF;">By</span> st.<span style="color: #202020;">name</span>
    , IsNull<span style="color: #808080;">&#40;</span>ix.<span style="color: #202020;">name</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
    , ix.<span style="color: #FF00FF;">object_id</span>
    , ix.<span style="color: #202020;">index_id</span>
	, <span style="color: #0000FF;">Cast</span><span style="color: #808080;">&#40;</span>
        <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span> <span style="color: #000;">1</span> 
                <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">'clustered'</span> 
            <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">index_id</span> <span style="color: #808080;">=</span><span style="color: #000;">0</span>
                <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">'heap'</span>
            <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">'nonclustered'</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">ignore_dup_key</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', ignore duplicate keys'</span> 
                <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">is_unique</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', unique'</span> 
                <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span>
		<span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> ix.<span style="color: #202020;">is_primary_key</span> <span style="color: #808080;">&lt;&gt;</span> <span style="color: #000;">0</span> 
            <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">', primary key'</span> <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">End</span> <span style="color: #0000FF;">As</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">210</span><span style="color: #808080;">&#41;</span>
        <span style="color: #808080;">&#41;</span>
    , ix.<span style="color: #202020;">filter_definition</span>
    , IsNull<span style="color: #808080;">&#40;</span>cte.<span style="color: #202020;">partition_scheme_name</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
    , IsNull<span style="color: #808080;">&#40;</span>cte.<span style="color: #202020;">partition_function_name</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>
<span style="color: #0000FF;">Order</span> <span style="color: #0000FF;">By</span> table_name
    , index_id;</pre></div></div>

<p>You may need to create some indexes to see this in AdventureWorks:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">NonClustered</span> <span style="color: #0000FF;">Index</span> IX_Sales_SalesOrderHeader_filtered_2005
    <span style="color: #0000FF;">On</span> Sales.<span style="color: #202020;">SalesOrderHeader</span><span style="color: #808080;">&#40;</span>AccountNumber<span style="color: #808080;">&#41;</span>
    Include <span style="color: #808080;">&#40;</span>CustomerID, SalesPersonID<span style="color: #808080;">&#41;</span>
    <span style="color: #0000FF;">Where</span> OrderDate <span style="color: #808080;">&gt;=</span> <span style="color: #FF0000;">'2005-01-01'</span>
        And OrderDate <span style="color: #808080;">&lt;</span> <span style="color: #FF0000;">'2006-01-01'</span>;</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">table_name           index_name                               object_id   index_id    index_description                   indexed_columns      included_columns               filter_definition                                            partition_scheme_name partition_count row_count
-------------------- ---------------------------------------- ----------- ----------- ----------------------------------- -------------------- ------------------------------ ------------------------------------------------------------ --------------------- --------------- --------------------
SalesOrderHeader     PK_SalesOrderHeader_SalesOrderID         1010102639  1           clustered, unique, primary key      SalesOrderID                                        NULL                                                                               1               31465
SalesOrderHeader     AK_SalesOrderHeader_rowguid              1010102639  2           nonclustered, unique                rowguid                                             NULL                                                                               1               31465
SalesOrderHeader     AK_SalesOrderHeader_SalesOrderNumber     1010102639  3           nonclustered, unique                SalesOrderNumber                                    NULL                                                                               1               31465
SalesOrderHeader     IX_SalesOrderHeader_CustomerID           1010102639  5           nonclustered                        CustomerID                                          NULL                                                                               1               31465
SalesOrderHeader     IX_SalesOrderHeader_SalesPersonID        1010102639  6           nonclustered                        SalesPersonID                                       NULL                                                                               1               31465
SalesOrderHeader     IX_Sales_SalesOrderHeader_filtered_2005  1010102639  13          nonclustered                        AccountNumber        CustomerID, SalesPersonID      ([OrderDate]&gt;='2005-01-01' AND [OrderDate]&lt;'2006-01-01')                           1               1379</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2010/06/index-interrogation-for-sql-server-2008/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Undocumented Function in SQL 2008</title>
		<link>http://sqlfool.com/2009/09/undocumented-function-in-sql-2008/</link>
		<comments>http://sqlfool.com/2009/09/undocumented-function-in-sql-2008/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 01:39:52 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[SQL 2008]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[2008]]></category>
		<category><![CDATA[pages]]></category>
		<category><![CDATA[undocumented commands]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=1154</guid>
		<description><![CDATA[If you&#8217;ve been following my blog for a little while, you&#8217;ll know that I&#8217;m a fan of SQL Server internals. There&#8217;s a lot that can be learned or better understood by rolling up your sleeves and getting into the nitty-gritty of data pages (i.e. see my post on Overhead in Non-Unique Clustered Indexes). So imagine [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve been following my blog for a little while, you&#8217;ll know that I&#8217;m a fan of SQL Server internals.  There&#8217;s a lot that can be learned or better understood by rolling up your sleeves and getting into the nitty-gritty of data pages (i.e. see my post on <a href="http://sqlfool.com/2009/05/overhead-i-non-unique-clustered-indexes/" target="_blank">Overhead in Non-Unique Clustered Indexes</a>).  So imagine how happy I was when my co-worker Jeff shared an undocumented function with me today that retrieves the file number, page number, and slot number of a single record.  Very cool!  Well, at least to me.  So now let&#8217;s see how you can use it.</p>
<p>The fn_physLocCracker function can be called in the following way:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Select</span> <span style="color: #0000FF;">Top</span> <span style="color: #000;">100</span> plc.<span style="color: #808080;">*</span>, soh.<span style="color: #202020;">SalesOrderID</span>
<span style="color: #0000FF;">From</span> Sales.<span style="color: #202020;">SalesOrderHeader</span> <span style="color: #0000FF;">As</span> soh
Cross Apply sys.<span style="color: #202020;">fn_physLocCracker</span> <span style="color: #808080;">&#40;</span><span style="color: #808080;">%%</span>physloc<span style="color: #808080;">%%</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">As</span> plc;</pre></div></div>

<p>Results (just a sample):</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">file_id     page_id     slot_id     SalesOrderID
----------- ----------- ----------- ------------
1           14032       0           43659
1           14032       1           43660
1           14032       2           43661
1           14032       3           43662
1           14032       4           43663</pre></div></div>

<p>If you look at the <a href="http://msdn.microsoft.com/en-us/library/ms176112.aspx" target="_blank">sp_helptext</a> for sys.fn_physLocCracker, %%physloc%% is apparently a virtual column that contains information on where the record is stored.  In fact, you can even append %%physloc%% to your column list if you want to see how the information is stored.  But for our purposes, we now have a file number, page number, and slot number.  What do we do with it?</p>
<p>Well, you can use the <a href="http://sqlfool.com/2009/05/page-internals-investigation-proc/" target="_blank">investigation proc I wrote</a> to retrieve the actual data page:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Execute</span> dba_viewPageData_sp 
      @databaseName <span style="color: #808080;">=</span> <span style="color: #FF0000;">'AdventureWorks'</span>
    , @fileNumber <span style="color: #808080;">=</span> <span style="color: #000;">1</span>
    , @pageNumber <span style="color: #808080;">=</span> <span style="color: #000;">14032</span>;</pre></div></div>

<p>Results (just a sample):</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
&nbsp;
SalesOrderID = 43659                 
&nbsp;
Slot 0 Column 2 Offset 0x8 Length 1 Length (physical) 1
&nbsp;
RevisionNumber = 1                   
&nbsp;
Slot 0 Column 3 Offset 0x9 Length 8 Length (physical) 8
&nbsp;
OrderDate = 2001-07-01 00:00:00.000  
&nbsp;
Slot 0 Column 4 Offset 0x11 Length 8 Length (physical) 8
&nbsp;
DueDate = 2001-07-13 00:00:00.000</pre></div></div>

<p>Neat, huh?  So why would you use it to look up the data page and file number when you can just pass the table name and index name to my proc and retrieve data pages?  Well, my investigation proc will retrieve data pages for any index type &#8212; the fn_physLocCracker function will only retrieve data for the clustered index &#8212; but it will not retrieve the data page for a specific record.  So just something to be aware of.</p>
<p>That&#8217;s all for now.  Back to the #24HoursOfPASS!  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2009/09/undocumented-function-in-sql-2008/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Overhead in Non-Unique Clustered Indexes</title>
		<link>http://sqlfool.com/2009/05/overhead-i-non-unique-clustered-indexes/</link>
		<comments>http://sqlfool.com/2009/05/overhead-i-non-unique-clustered-indexes/#comments</comments>
		<pubDate>Thu, 21 May 2009 13:22:29 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[Performance & Tuning]]></category>
		<category><![CDATA[SQL 2008]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[indexes]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=961</guid>
		<description><![CDATA[I&#8217;ve received a couple of questions regarding my article, Performance Considerations of Data Types, and the overhead associated with non-unique clustered indexes. I started to respond via e-mail, but my response was so long I decided to turn it into a blog post instead. I should start by clarifying that non-unique clustered indexes do not [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve received a couple of questions regarding my article, <a href="http://sqlfool.com/2009/05/performance-considerations-of-data-types/" target="_blank">Performance Considerations of Data Types</a>, and the overhead associated with non-unique clustered indexes.  I started to respond via e-mail, but my response was so long I decided to turn it into a blog post instead.  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>I should start by clarifying that <strong>non-unique clustered indexes do not necessarily consume more space and overhead</strong>; it depends on the data stored.  If you have duplicate clustered key values, the first instance of the value will be handled as though it were unique.  Any subsequent values, however, will incur overhead to manage the uniquifier that SQL Server adds to maintain row uniqueness.  This same overhead is also incurred in non-clustered indexes, too, adding to the overall expense of this approach.</p>
<p>I think it helps to actually look at the data, so let&#8217;s walk through a few different common scenarios.  We&#8217;ll create a table with a unique clustered index, a table with a non-unique clustered index but no duplicates, and a table with duplicate key values.  </p>
<p>Also, a little warning that I started to write this in SQL Server 2008, and since I&#8217;m on a 2008 kick, I decided to leave it that way.  You can modify this pretty easily to work in 2005, if necessary.</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Use</span> sandbox;
Go
&nbsp;
<span style="color: #008080;">/* Unique, clustered index, no duplicate values */</span>
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Table</span> dbo.<span style="color: #202020;">uniqueClustered</span>
<span style="color: #808080;">&#40;</span>
      myDate    <span style="color: #0000FF;">date</span>        Not Null
    , myNumber  <span style="color: #0000FF;">int</span>         Not Null
    , myColumn  <span style="color: #0000FF;">char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">995</span><span style="color: #808080;">&#41;</span>   Not Null
<span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Unique</span> <span style="color: #0000FF;">Clustered</span> <span style="color: #0000FF;">Index</span> CIX_uniqueClustered
    <span style="color: #0000FF;">On</span> dbo.<span style="color: #202020;">uniqueClustered</span><span style="color: #808080;">&#40;</span>myDate<span style="color: #808080;">&#41;</span>;
&nbsp;
&nbsp;
<span style="color: #008080;">/* Non-unique clustered index, but no duplicate values */</span>
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Table</span> dbo.<span style="color: #202020;">nonUniqueNoDups</span>
<span style="color: #808080;">&#40;</span>
      myDate    <span style="color: #0000FF;">date</span>        Not Null
    , myNumber  <span style="color: #0000FF;">int</span>         Not Null
    , myColumn  <span style="color: #0000FF;">char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">995</span><span style="color: #808080;">&#41;</span>   Not Null
<span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Clustered</span> <span style="color: #0000FF;">Index</span> CIX_nonUniqueNoDups
    <span style="color: #0000FF;">On</span> dbo.<span style="color: #202020;">nonUniqueNoDups</span><span style="color: #808080;">&#40;</span>myDate<span style="color: #808080;">&#41;</span>;
&nbsp;
&nbsp;
<span style="color: #008080;">/* Non-unique clustered index, duplicate values */</span>
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Table</span> dbo.<span style="color: #202020;">nonUniqueDuplicates</span>
<span style="color: #808080;">&#40;</span>
      myDate    <span style="color: #0000FF;">date</span>        Not Null
    , myNumber  <span style="color: #0000FF;">int</span>         Not Null
    , myColumn  <span style="color: #0000FF;">char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">995</span><span style="color: #808080;">&#41;</span>   Not Null
<span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Clustered</span> <span style="color: #0000FF;">Index</span> CIX_nonUniqueDuplicates
    <span style="color: #0000FF;">On</span> dbo.<span style="color: #202020;">nonUniqueDuplicates</span><span style="color: #808080;">&#40;</span>myDate<span style="color: #808080;">&#41;</span>;</pre></div></div>

<p>I&#8217;m going to use the <a href="http://msdn.microsoft.com/en-us/library/bb630352.aspx" target="_blank">date</a> data type in 2008 for my clustered index key.  To ensure uniqueness for the first two tables, I&#8217;ll iterate through a few years&#8217; worth of dates.  This is typical of what you may see in a data mart, where you&#8217;d have one record with an aggregation of each day&#8217;s data.  For the table with duplicate values, I&#8217;m going to insert the same date for each row.</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #008080;">/* Populate some test data */</span>
<span style="color: #0000FF;">Set</span> <span style="color: #0000FF;">NoCount</span> <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Declare</span> @myDate <span style="color: #0000FF;">date</span> <span style="color: #808080;">=</span> <span style="color: #FF0000;">'1990-01-01'</span>
    , @myNumber <span style="color: #0000FF;">int</span> <span style="color: #808080;">=</span> <span style="color: #000;">1</span>;
&nbsp;
<span style="color: #0000FF;">While</span> @myDate <span style="color: #808080;">&lt;</span> <span style="color: #FF0000;">'2010-01-01'</span>
<span style="color: #0000FF;">Begin</span>
&nbsp;
    <span style="color: #0000FF;">Insert</span> <span style="color: #0000FF;">Into</span> dbo.<span style="color: #202020;">uniqueClustered</span>
    <span style="color: #0000FF;">Select</span> @myDate, @myNumber, <span style="color: #FF0000;">'data'</span>;
&nbsp;
    <span style="color: #0000FF;">Insert</span> <span style="color: #0000FF;">Into</span> dbo.<span style="color: #202020;">nonUniqueNoDups</span>
    <span style="color: #0000FF;">Select</span> @myDate, @myNumber, <span style="color: #FF0000;">'data'</span>;
&nbsp;
    <span style="color: #0000FF;">Insert</span> <span style="color: #0000FF;">Into</span> dbo.<span style="color: #202020;">nonUniqueDuplicates</span>
    <span style="color: #0000FF;">Select</span> <span style="color: #FF0000;">'2009-01-01'</span>, @myNumber, <span style="color: #FF0000;">'data'</span>;
&nbsp;
    <span style="color: #0000FF;">Select</span> @myDate <span style="color: #808080;">=</span> <span style="color: #FF00FF;">DateAdd</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">day</span>, <span style="color: #000;">1</span>, @myDate<span style="color: #808080;">&#41;</span>
        , @myNumber <span style="color: #808080;">+=</span> <span style="color: #000;">1</span>;
&nbsp;
<span style="color: #0000FF;">End</span>;</pre></div></div>

<p>After running the above script, each table should have 7,305 records.  This is obviously pretty small for a table, but it&#8217;ll serve our purposes.  Now let&#8217;s take a look at the size of our tables:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #008080;">/* Look at the details of our indexes */</span>
&nbsp;
<span style="color: #008080;">/* Unique, clustered index, no duplicate values */</span>
<span style="color: #0000FF;">Select</span> <span style="color: #FF0000;">'unique'</span> <span style="color: #0000FF;">As</span> <span style="color: #FF0000;">'type'</span>, page_count, avg_page_space_used_in_percent, record_count
    , min_record_size_in_bytes, max_record_size_in_bytes
<span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">dm_db_index_physical_stats</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">DB_ID</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF00FF;">Object_ID</span><span style="color: #808080;">&#40;</span>N<span style="color: #FF0000;">'uniqueClustered'</span><span style="color: #808080;">&#41;</span>, Null, Null, N<span style="color: #FF0000;">'Detailed'</span><span style="color: #808080;">&#41;</span> 
<span style="color: #0000FF;">Where</span> index_level <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
<span style="color: #0000FF;">Union</span> All
<span style="color: #008080;">/* Non-unique clustered index, but no duplicate values */</span>
<span style="color: #0000FF;">Select</span> <span style="color: #FF0000;">'non-unique, no dups'</span>, page_count, avg_page_space_used_in_percent, record_count
    , min_record_size_in_bytes, max_record_size_in_bytes
<span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">dm_db_index_physical_stats</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">DB_ID</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF00FF;">Object_ID</span><span style="color: #808080;">&#40;</span>N<span style="color: #FF0000;">'nonUniqueNoDups'</span><span style="color: #808080;">&#41;</span>, Null, Null, N<span style="color: #FF0000;">'Detailed'</span><span style="color: #808080;">&#41;</span> 
<span style="color: #0000FF;">Where</span> index_level <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
<span style="color: #0000FF;">Union</span> All
<span style="color: #008080;">/* Non-unique clustered index, duplicate values */</span>
<span style="color: #0000FF;">Select</span> <span style="color: #FF0000;">'duplicates'</span>, page_count, avg_page_space_used_in_percent, record_count
    , min_record_size_in_bytes, max_record_size_in_bytes
<span style="color: #0000FF;">From</span> sys.<span style="color: #202020;">dm_db_index_physical_stats</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">DB_ID</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF00FF;">Object_ID</span><span style="color: #808080;">&#40;</span>N<span style="color: #FF0000;">'nonUniqueDuplicates'</span><span style="color: #808080;">&#41;</span>, Null, Null, N<span style="color: #FF0000;">'Detailed'</span><span style="color: #808080;">&#41;</span> 
<span style="color: #0000FF;">Where</span> index_level <span style="color: #808080;">=</span> <span style="color: #000;">0</span>;</pre></div></div>

<p>Here&#8217;s the results:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">type                page_count           avg_page_space_used_in_percent record_count         min_record_size_in_bytes max_record_size_in_bytes
------------------- -------------------- ------------------------------ -------------------- ------------------------ ------------------------
unique              914                  99.8055102545095               7305                 1009                     1009
non-unique, no dups 914                  99.8055102545095               7305                 1009                     1009
duplicates          1044                 88.066036570299                7305                 1009                     1017</pre></div></div>

<p>I want to point out a couple of things.  First, there is no difference in the number of pages between the non-unique clustered index with no duplicates ([nonUniqueNoDups]) and the unique clustered index ([uniqueClustered]).  The table with duplicate clustered key values, however, requires 14% more pages to store the same amount of data.  Secondly, the [max_record_size_in_bytes] of the [nonUniqueDuplicates] table is 8 bytes more than that of the other two.  We&#8217;ll discuss why in a minute.  </p>
<p>Now let&#8217;s take a look at the actual data pages.  For this, I&#8217;m going to use my <a href="http://sqlfool.com/2009/05/page-internals-investigation-proc/" target="_blank">page internals proc</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">EXECUTE</span> dbo<span style="color: #66cc66;">.</span>dba_viewPageData_sp
      @databaseName <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'sandbox'</span>
    <span style="color: #66cc66;">,</span> @tableName    <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'sandbox.dbo.uniqueClustered'</span>
    <span style="color: #66cc66;">,</span> @indexName    <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'CIX_uniqueClustered'</span>;</pre></div></div>

<p>I&#8217;m not going to post the entire results here, but I want to draw your attention to &#8220;m_slotCnt = 8&#8243;, which is near the top of the page.  That means 8 records are stored on this page.  Also, when you look near the end of the first record (Slot 0), you should see the following results:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Slot 0 Offset 0x60 Length 1009
Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     Record Size = 1009
Memory Dump @0x00A9C060
00000000:   1000ee03 c3150b01 00000064 61746120 †..î.Ã......data 
[...]
000003F0:   00†††††††††††††††††††††††††††††††††††.  
&nbsp;
Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3
myDate = 1990-01-01                  
&nbsp;
Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4
myNumber = 1                         
&nbsp;
Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995
myColumn = data</pre></div></div>

<p>Now let&#8217;s look at the table that has a non-unique clustered index but no duplicates:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Execute</span> dbo.<span style="color: #202020;">dba_viewPageData_sp</span>
      @databaseName <span style="color: #808080;">=</span> <span style="color: #FF0000;">'sandbox'</span>
    , @tableName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'sandbox.dbo.nonUniqueNoDups'</span>
    , @indexName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'CIX_nonUniqueNoDups'</span>;</pre></div></div>

<p>The m_slotCnt count is also 8 for this page.  This time, let&#8217;s glance at the first and second records (Slot 0 and 1 respectively):</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Slot 0 Offset 0x60 Length 1009
Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     Record Size = 1009
Memory Dump @0x62FDC060
00000000:   1000ee03 c3150b01 00000064 61746120 †..î.Ã......data    
[...]
000003F0:   00†††††††††††††††††††††††††††††††††††.                        
&nbsp;
Slot 0 Column 0 Offset 0x0 Length 4 Length (physical) 0
UNIQUIFIER = 0                       
&nbsp;
Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3
myDate = 1990-01-01                  
&nbsp;
Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4
myNumber = 1                         
&nbsp;
Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995
myColumn = data
&nbsp;
&nbsp;
Slot 1 Offset 0x451 Length 1009
Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     Record Size = 1009
Memory Dump @0x62FDC451
&nbsp;
00000000:   1000ee03 c4150b02 00000064 61746120 †..î.Ä......data          
[...]
000003F0:   00†††††††††††††††††††††††††††††††††††.                        
&nbsp;
Slot 1 Column 0 Offset 0x0 Length 4 Length (physical) 0
UNIQUIFIER = 0                       
&nbsp;
Slot 1 Column 1 Offset 0x4 Length 3 Length (physical) 3
myDate = 1990-01-02                  
&nbsp;
Slot 1 Column 2 Offset 0x7 Length 4 Length (physical) 4
myNumber = 2                         
&nbsp;
Slot 1 Column 3 Offset 0xb Length 995 Length (physical) 995
myColumn = data</pre></div></div>

<p>We now see a new addition to the row, &#8220;UNIQUIFIER = 0.&#8221;  This is SQL Server&#8217;s way of managing row uniqueness internally.  You&#8217;ll notice that, because the clustered key values are unique, the UNIQUIFIER is set to 0 and the row size is still 1009; for all intents and purposes, the UNIQUIFIER is not consuming any space.</p>
<p><strong>Update:</strong>  The DBCC God himself, <a href="http://www.sqlskills.com/blogs/paul/" target="_blank">Paul Randal</a>, explained that non-dupes actually have a NULL UNIQUIFIER, which DBCC PAGE displays as a 0.  Thanks for explaining, Paul!  I wondered about that but chalked it up to SQL voodoo.  </p>
<p>Now let&#8217;s look at our final case, a non-unique clustered index with duplicate key values:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Execute</span> dbo.<span style="color: #202020;">dba_viewPageData_sp</span>
      @databaseName <span style="color: #808080;">=</span> <span style="color: #FF0000;">'sandbox'</span>
    , @tableName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'sandbox.dbo.nonUniqueDuplicates'</span>
    , @indexName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'CIX_nonUniqueDuplicates'</span>;</pre></div></div>

<p>Here&#8217;s where things get interesting.  The m_slotCnt value is now 7, which means we&#8217;re now storing 1 record less per page.  Let&#8217;s look at the details:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">Slot 0 Offset 0x60 Length 1009
Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP     Record Size = 1009
Memory Dump @0x00A9C060
00000000:   1000ee03 df300b01 00000064 61746120 †..î.ß0.....data  
[...]
000003F0:   00†††††††††††††††††††††††††††††††††††.                        
&nbsp;
Slot 0 Column 0 Offset 0x0 Length 4 Length (physical) 0
UNIQUIFIER = 0                       
&nbsp;
Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3
myDate = 2009-01-01                  
&nbsp;
Slot 0 Column 2 Offset 0x7 Length 4 Length (physical) 4
myNumber = 1                         
&nbsp;
Slot 0 Column 3 Offset 0xb Length 995 Length (physical) 995
myColumn = data
&nbsp;
&nbsp;
Slot 1 Offset 0x451 Length 1017
&nbsp;
Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
Record Size = 1017                   
Memory Dump @0x00A9C451
00000000:   3000ee03 df300b02 00000064 61746120 †0.î.ß0.....data  
[...]
000003F0:   000100f9 03010000 00†††††††††††††††††...ù.....                
&nbsp;
Slot 1 Column 0 Offset 0x3f5 Length 4 Length (physical) 4
UNIQUIFIER = 1                       
&nbsp;
Slot 1 Column 1 Offset 0x4 Length 3 Length (physical) 3
myDate = 2009-01-01                  
&nbsp;
Slot 1 Column 2 Offset 0x7 Length 4 Length (physical) 4
myNumber = 2                         
&nbsp;
Slot 1 Column 3 Offset 0xb Length 995 Length (physical) 995
myColumn = data</pre></div></div>

<p>The first record, Slot 0, looks exactly the same as in the previous table; the UNIQUIFIER is 0 and the row size is 1009.  The second record (Slot 1), however, now has a UNIQUIFIER value of 1 and the row size is 1017.  If you notice, the &#8220;Record Attributes&#8221; of Slot 1 are also different, with the addition of &#8220;VARIABLE_COLUMNS.&#8221;  This is because the UNIQUIFIER is stored as a variable column.  The extra 8 bytes of overhead break down to 4 bytes to store the UNIQUIFIER, 2 bytes to store the variable column offset, and 2 bytes to store the variable count.  The tables we created used all fixed-length columns; you may notice some minor overhead differences if your table already contains variable columns.</p>
<p>To summarize, there is indeed a difference in the page structure between a unique clustered index and a non-unique clustered index; however, there&#8217;s only a possible performance and space impact when storing duplicate clustered key values.  So there you go, more detail than you ever wanted to know about clustered indexes and uniqueness!</p>
]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2009/05/overhead-i-non-unique-clustered-indexes/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Page Internals &#8211; Investigation Proc</title>
		<link>http://sqlfool.com/2009/05/page-internals-investigation-proc/</link>
		<comments>http://sqlfool.com/2009/05/page-internals-investigation-proc/#comments</comments>
		<pubDate>Wed, 06 May 2009 19:01:11 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[T-SQL Scripts]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=935</guid>
		<description><![CDATA[As many of you know, I like to crawl around in page internals in my free time. It can be very enlightening, or just a good check to make sure that what you think is happening, is actually happening. To help with this process, I&#8217;ve created myself a little stored procedure that I can simply [...]]]></description>
			<content:encoded><![CDATA[<p>As many of you know, I like to crawl around in page internals in my free time.  It can be very enlightening, or just a good check to make sure that what you think is happening, is actually happening.  To help with this process, I&#8217;ve created myself a little stored procedure that I can simply pass a few parameters to and have it return the page data for me.  So for those <span style="text-decoration: line-through;">who don&#8217;t have anything better to do</span> who are as interested in page internals as I am, here&#8217;s my proc:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Procedure</span> dbo.<span style="color: #202020;">dba_viewPageData_sp</span>
&nbsp;
        <span style="color: #008080;">/* Declare Parameters */</span>
          @databaseName <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">128</span><span style="color: #808080;">&#41;</span>
        , @tableName    <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">128</span><span style="color: #808080;">&#41;</span>    <span style="color: #808080;">=</span> Null <span style="color: #008080;">-- database.schema.tableName</span>
        , @indexName    <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">128</span><span style="color: #808080;">&#41;</span>    <span style="color: #808080;">=</span> Null
        , @fileNumber   <span style="color: #0000FF;">int</span>             <span style="color: #808080;">=</span> Null
        , @pageNumber   <span style="color: #0000FF;">int</span>             <span style="color: #808080;">=</span> Null
        , @printOption  <span style="color: #0000FF;">int</span>             <span style="color: #808080;">=</span> <span style="color: #000;">3</span>    <span style="color: #008080;">-- 0, 1, 2, or 3</span>
        , @pageType     <span style="color: #0000FF;">char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">4</span><span style="color: #808080;">&#41;</span>         <span style="color: #808080;">=</span> <span style="color: #FF0000;">'Leaf'</span> <span style="color: #008080;">-- Leaf, Root, or IAM</span>
&nbsp;
<span style="color: #0000FF;">As</span>
<span style="color: #008080;">/*********************************************************************************
    Name:       dba_viewPageData_sp
&nbsp;
    Author:     Michelle Ufford
&nbsp;
    Purpose:    Retrieves page data for the specified table/page.
&nbsp;
    Notes:      Can pass either the table name or the pageID, but must pass one, or
                you'll end up with no results. 
                If the table name is passed, it will return the first page.
&nbsp;
        @tableName must be '&lt;databaseName&gt;.&lt;schemaName&gt;.&lt;tableName&gt;' in order to
            function correctly for cross-database joins.  
&nbsp;
        @printOption can be one of following values:
            0 - print just the page header
            1 - page header plus per-row hex dumps and a dump of the page slot array
            2 - page header plus whole page hex dump
            3 - page header plus detailed per-row interpretation
&nbsp;
        Page Options borrowed from: 
        https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx
&nbsp;
        @pageType must be one of the following values:
            Leaf - returns the first page of the leaf level of your index or heap
            Root - returns the root page of your index
            IAM - returns the index allocation map chain for your index or heap
&nbsp;
        Conversions borrowed from:
        http://sqlskills.com/blogs/paul/post/Inside-The-Storage-Engine-
        sp_AllocationMetadata-putting-undocumented-system-catalog-views-to-work.aspx
&nbsp;
    Called by:  DBA
&nbsp;
    Date        User    Description
    ----------------------------------------------------------------------------
    2009-05-06  MFU     Initial release for public consumption
*********************************************************************************
    Exec dbo.dba_viewPageData_sp
          @databaseName = 'AdventureWorks'
        , @tableName    = 'AdventureWorks.Sales.SalesOrderDetail'
        , @indexName    = 'IX_SalesOrderDetail_ProductID'
        --, @fileNumber   = 1
        --, @pageNumber   = 38208
        , @printOption  = 3
        , @pageType     = 'Root';
*********************************************************************************/</span>
&nbsp;
<span style="color: #0000FF;">Set</span> <span style="color: #0000FF;">NoCount</span> <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> XACT_Abort <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> Ansi_Padding <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> Ansi_Warnings <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> ArithAbort <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> Concat_Null_Yields_Null <span style="color: #0000FF;">On</span>;
<span style="color: #0000FF;">Set</span> Numeric_RoundAbort <span style="color: #0000FF;">Off</span>;
&nbsp;
<span style="color: #0000FF;">Begin</span>
&nbsp;
    <span style="color: #0000FF;">Declare</span> @fileID         <span style="color: #0000FF;">int</span>
        , @pageID           <span style="color: #0000FF;">int</span>
        , @sqlStatement     <span style="color: #0000FF;">nvarchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1200</span><span style="color: #808080;">&#41;</span>
        , @sqlParameters    <span style="color: #0000FF;">nvarchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">255</span><span style="color: #808080;">&#41;</span>
        , @errorMessage     <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span>;
&nbsp;
    <span style="color: #0000FF;">Begin</span> Try
&nbsp;
        <span style="color: #0000FF;">If</span> @fileNumber <span style="color: #0000FF;">Is</span> Null And @pageNumber <span style="color: #0000FF;">Is</span> Null And @tableName <span style="color: #0000FF;">Is</span> Null
        <span style="color: #0000FF;">Begin</span>
            <span style="color: #0000FF;">Set</span> @errorMessage <span style="color: #808080;">=</span> <span style="color: #FF0000;">'You must provide either a file/page number, or a table name!'</span>;
            <span style="color: #0000FF;">RaisError</span><span style="color: #808080;">&#40;</span>@errorMessage, <span style="color: #000;">16</span>, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span>;
        <span style="color: #0000FF;">End</span>;
&nbsp;
        <span style="color: #0000FF;">If</span> @pageType Not In <span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'Leaf'</span>, <span style="color: #FF0000;">'Root'</span>, <span style="color: #FF0000;">'IAM'</span><span style="color: #808080;">&#41;</span>
        <span style="color: #0000FF;">Begin</span>
            <span style="color: #0000FF;">Set</span> @errorMessage <span style="color: #808080;">=</span> <span style="color: #FF0000;">'You have entered an invalid page type; valid options are &quot;Leaf&quot;, &quot;Root&quot;, or &quot;IAM&quot;'</span>;
            <span style="color: #0000FF;">RaisError</span><span style="color: #808080;">&#40;</span>@errorMessage, <span style="color: #000;">16</span>, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span>;
        <span style="color: #0000FF;">End</span>;
&nbsp;
        <span style="color: #0000FF;">If</span> @fileNumber <span style="color: #0000FF;">Is</span> Null Or @pageNumber <span style="color: #0000FF;">Is</span> Null
        <span style="color: #0000FF;">Begin</span>
&nbsp;
            <span style="color: #0000FF;">Set</span> @sqlStatement <span style="color: #808080;">=</span> 
            <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> @pageType <span style="color: #808080;">=</span> <span style="color: #FF0000;">'Leaf'</span> <span style="color: #0000FF;">Then</span>
                <span style="color: #FF0000;">'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, 
                    SubString (au.first_page, 6, 1) +
                    SubString (au.first_page, 5, 1)))
                , @p_pageID = Convert (varchar(20), Convert (int, 
                     SubString (au.first_page, 4, 1) +
                     SubString (au.first_page, 3, 1) +
                     SubString (au.first_page, 2, 1) +
                     SubString (au.first_page, 1, 1)))'</span>
            <span style="color: #0000FF;">When</span> @pageType <span style="color: #808080;">=</span> <span style="color: #FF0000;">'Root'</span> <span style="color: #0000FF;">Then</span>
                <span style="color: #FF0000;">'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, 
                    SubString (au.root_page, 6, 1) +
                    SubString (au.root_page, 5, 1)))
                , @p_pageID = Convert (varchar(20), Convert (int, 
                     SubString (au.root_page, 4, 1) +
                     SubString (au.root_page, 3, 1) +
                     SubString (au.root_page, 2, 1) +
                     SubString (au.root_page, 1, 1)))'</span>
            <span style="color: #0000FF;">When</span> @pageType <span style="color: #808080;">=</span> <span style="color: #FF0000;">'IAM'</span> <span style="color: #0000FF;">Then</span>
                <span style="color: #FF0000;">'Select Top 1 @p_fileID = Convert (varchar(6), Convert (int, 
                    SubString (au.first_iam_page, 6, 1) +
                    SubString (au.first_iam_page, 5, 1)))
                , @p_pageID = Convert (varchar(20), Convert (int, 
                     SubString (au.first_iam_page, 4, 1) +
                     SubString (au.first_iam_page, 3, 1) +
                     SubString (au.first_iam_page, 2, 1) +
                     SubString (au.first_iam_page, 1, 1)))'</span>
            <span style="color: #0000FF;">End</span> <span style="color: #808080;">+</span> 
            <span style="color: #FF0000;">'From '</span> <span style="color: #808080;">+</span> <span style="color: #FF00FF;">QuoteName</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">ParseName</span><span style="color: #808080;">&#40;</span>@databaseName, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #808080;">+</span> <span style="color: #FF0000;">'.sys.indexes AS i
            Join '</span> <span style="color: #808080;">+</span> <span style="color: #FF00FF;">QuoteName</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">ParseName</span><span style="color: #808080;">&#40;</span>@databaseName, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #808080;">+</span> <span style="color: #FF0000;">'.sys.partitions AS p
                On i.[object_id] = p.[object_id]
                And i.index_id = p.index_id
            Join '</span> <span style="color: #808080;">+</span> <span style="color: #FF00FF;">QuoteName</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">ParseName</span><span style="color: #808080;">&#40;</span>@databaseName, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #808080;">+</span> <span style="color: #FF0000;">'.sys.system_internals_allocation_units AS au
                On p.hobt_id = au.container_id
            Where p.[object_id] = Object_ID(@p_tableName)
                And au.first_page &gt; 0x000000000000 '</span> 
                <span style="color: #808080;">+</span> <span style="color: #0000FF;">Case</span> <span style="color: #0000FF;">When</span> @indexName <span style="color: #0000FF;">Is</span> Null 
                    <span style="color: #0000FF;">Then</span> <span style="color: #FF0000;">';'</span> 
                    <span style="color: #0000FF;">Else</span> <span style="color: #FF0000;">'And i.name = @p_indexName;'</span> <span style="color: #0000FF;">End</span>;
&nbsp;
            <span style="color: #0000FF;">Set</span> @sqlParameters <span style="color: #808080;">=</span> <span style="color: #FF0000;">'@p_tableName varchar(128)
                                , @p_indexName varchar(128)
                                , @p_fileID int OUTPUT
                                , @p_pageID int OUTPUT'</span>;
&nbsp;
            <span style="color: #0000FF;">Execute</span> <span style="color: #AF0000;">sp_executeSQL</span> @sqlStatement
                        , @sqlParameters
                        , @p_tableName <span style="color: #808080;">=</span> @tableName
                        , @p_indexName <span style="color: #808080;">=</span> @indexName
                        , @p_fileID <span style="color: #808080;">=</span> @fileID <span style="color: #0000FF;">OUTPUT</span>
                        , @p_pageID <span style="color: #808080;">=</span> @pageID <span style="color: #0000FF;">OUTPUT</span>;
&nbsp;
            <span style="color: #0000FF;">End</span>
            <span style="color: #0000FF;">Else</span>
            <span style="color: #0000FF;">Begin</span>
                <span style="color: #0000FF;">Select</span> @fileID <span style="color: #808080;">=</span> @fileNumber
                    , @pageID <span style="color: #808080;">=</span> @pageNumber;
            <span style="color: #0000FF;">End</span>;
&nbsp;
        <span style="color: #0000FF;">DBCC</span> TraceOn <span style="color: #808080;">&#40;</span><span style="color: #000;">3604</span><span style="color: #808080;">&#41;</span>;
        <span style="color: #0000FF;">DBCC</span> Page <span style="color: #808080;">&#40;</span>@databaseName, @fileID, @pageID, @printOption<span style="color: #808080;">&#41;</span>;
        <span style="color: #0000FF;">DBCC</span> TraceOff <span style="color: #808080;">&#40;</span><span style="color: #000;">3604</span><span style="color: #808080;">&#41;</span>;
&nbsp;
    <span style="color: #0000FF;">End</span> Try
    <span style="color: #0000FF;">Begin</span> Catch
&nbsp;
        <span style="color: #0000FF;">Print</span> @errorMessage;
&nbsp;
    <span style="color: #0000FF;">End</span> Catch;
&nbsp;
    <span style="color: #0000FF;">Set</span> <span style="color: #0000FF;">NoCount</span> <span style="color: #0000FF;">Off</span>;
    <span style="color: #0000FF;">Return</span> <span style="color: #000;">0</span>;
<span style="color: #0000FF;">End</span>
Go</pre></div></div>

<p>This proc does have cross-database support, i.e. you can install it in your DBA database and use it to investigate data in other databases.  Here&#8217;s an example&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;">    <span style="color: #0000FF;">Exec</span> dbo.<span style="color: #202020;">dba_viewPageData_sp</span>
          @databaseName <span style="color: #808080;">=</span> <span style="color: #FF0000;">'AdventureWorks'</span>
        , @tableName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'AdventureWorks.Sales.SalesOrderDetail'</span>
        , @indexName    <span style="color: #808080;">=</span> <span style="color: #FF0000;">'IX_SalesOrderDetail_ProductID'</span>;</pre></div></div>

<p>&#8230; will return a nice data page:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">DBCC execution completed. If DBCC printed error messages, contact your system administrator.
&nbsp;
PAGE: (1:11000)
&nbsp;
BUFFER:
&nbsp;
BUF @0x0391F140
&nbsp;
bpage = 0x0C0C0000                   bhash = 0x00000000                   bpageno = (1:11000)
bdbid = 7                            breferences = 0                      bUse1 = 35177
bstat = 0x1c00009                    blog = 0x21212159                    bnext = 0x00000000</pre></div></div>

<p>[waits for the "oohs" and "aahs" to subside...]</p>
<p>I also give you the option to specify a specific page, in case you want to follow the page trail (i.e. m_nextPage).  I&#8217;m not really providing support for partitions, although I do have a little dirty piece of code to return a hobt with data if possible (i.e. &#8220;first_page > 0&#215;000000000000&#8243;).  </p>
<p><strong>Update:</strong> Special thanks to <a href="http://twitter.com/peschkaj" target="_blank">Jeremiah Peschka</a> and <a href="http://twitter.com/AdamMachanic" target="_blank">Adam Machanic</a> for showing me<br />
QUOTENAME(PARSENAME(@databaseName, 1))!  <img src='http://sqlfool.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Also, thanks to <a href="http://www.sqlskills.com/BLOGS/PAUL/" target="_blank">Paul Randal</a> for his excellent blog posts on this very topic!  Check out his blog post on <a href="https://blogs.msdn.com/sqlserverstorageengine/archive/2006/06/10/625659.aspx" target="_blank">DBCC Page</a>.  The conversion code was borrowed from his <a href="http://www.sqlskills.com/BLOGS/PAUL/post/Inside-The-Storage-Engine-sp_AllocationMetadata-putting-undocumented-system-catalog-views-to-work.aspx" target="_blank">sp_AllocationMetadata</a> proc.  </p>
<p><strong>Update 2:</strong> I&#8217;ve made some quick changes based on some feedback from Twitter.  Thanks for the suggestions and hopefully you enjoy the updates.  </p>
<p>Happy crawling!</p>
]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2009/05/page-internals-investigation-proc/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Page Splitting &amp; Rollbacks</title>
		<link>http://sqlfool.com/2009/04/page-splitting-rollbacks/</link>
		<comments>http://sqlfool.com/2009/04/page-splitting-rollbacks/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 13:38:11 +0000</pubDate>
		<dc:creator>Michelle Ufford</dc:creator>
				<category><![CDATA[Internals]]></category>
		<category><![CDATA[Performance & Tuning]]></category>
		<category><![CDATA[Syndication]]></category>
		<category><![CDATA[fragmentation]]></category>
		<category><![CDATA[page splitting]]></category>
		<category><![CDATA[rollbacks]]></category>

		<guid isPermaLink="false">http://sqlfool.com/?p=794</guid>
		<description><![CDATA[So while I was at the grocery store last night, my mind wandered to SQL Server. This time, I was pondering what happens to a page split if the transaction is rolled back. I didn&#8217;t know the answer, but my guess was that the page split remained, since it would be less expensive for SQL [...]]]></description>
			<content:encoded><![CDATA[<p>So while I was at the grocery store last night, my mind wandered to SQL Server.  This time, I was pondering what happens to a page split if the transaction is rolled back.  I didn&#8217;t know the answer, but my guess was that the page split remained, since it would be less expensive for SQL Server to leave the data where it was sitting.  Also, in theory, if the page split occurred once, it could need to occur again, so why undergo that same expense twice?</p>
<p>I decided to run a simple test to see what would happen.  First, I created a really wide table and tossed 4 rows into it:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Create</span> <span style="color: #0000FF;">Table</span> myTable
<span style="color: #808080;">&#40;</span>
      id            <span style="color: #0000FF;">int</span> <span style="color: #0000FF;">Primary</span> <span style="color: #0000FF;">Key</span>
    , wideColumn    <span style="color: #0000FF;">char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span> 
<span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">Insert</span> <span style="color: #0000FF;">Into</span> myTable
<span style="color: #0000FF;">Select</span> <span style="color: #000;">1</span>, <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'A'</span>, <span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">Union</span> All
<span style="color: #0000FF;">Select</span> <span style="color: #000;">2</span>, <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'B'</span>, <span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">Union</span> All
<span style="color: #0000FF;">Select</span> <span style="color: #000;">4</span>, <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'C'</span>, <span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">Union</span> All
<span style="color: #0000FF;">Select</span> <span style="color: #000;">5</span>, <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'D'</span>, <span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span>;</pre></div></div>

<p>I left an open spot for id=3, so I can force a page split.  Next, I looked at the page data <a href="http://sqlfool.com/2009/02/view_page_data/" target="_blank">using the script I posted in February</a>.</p>
<p>Here&#8217;s what I saw:</p>
<div id="attachment_795" class="wp-caption alignnone" style="width: 460px"><a href="http://sqlfool.com/wp-content/uploads/2009/04/before.jpg"><img src="http://sqlfool.com/wp-content/uploads/2009/04/before_small.jpg" alt="Before" title="20090408_before_small" width="450" height="451" class="size-full wp-image-795" /></a><p class="wp-caption-text">Before</p></div>
<p>Pay attention to the 2 items boxed in red.  m_slotCnt tells us how many records are on the page, and m_nextPage tells us the address of the next page.  As you may have guessed, a m_nextPage value of 0:0 means you&#8217;re looking at the last page allocated to the object.  </p>
<p>Now let&#8217;s insert a record, roll it back, and see what happens:</p>

<div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">Begin</span> <span style="color: #0000FF;">Transaction</span>;
&nbsp;
<span style="color: #0000FF;">Insert</span> <span style="color: #0000FF;">Into</span> myTable
<span style="color: #0000FF;">Select</span> <span style="color: #000;">3</span>, <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'E'</span>, <span style="color: #000;">2000</span><span style="color: #808080;">&#41;</span>;
&nbsp;
<span style="color: #0000FF;">Rollback</span> <span style="color: #0000FF;">Transaction</span>;</pre></div></div>

<p>I ran my DBCC Page command again and here&#8217;s what I saw:</p>
<div id="attachment_802" class="wp-caption alignnone" style="width: 460px"><a href="http://sqlfool.com/wp-content/uploads/2009/04/after.jpg"><img src="http://sqlfool.com/wp-content/uploads/2009/04/after_small.jpg" alt="After" title="after_small" width="450" height="444" class="size-full wp-image-802" /></a><p class="wp-caption-text">After</p></div>
<p>As you can see, m_slotCnt is now 2, and m_nextPage is no longer 0:0 (although your actual page number will probably be different than mine).  If I pull up the new page, I find my 2 relocated records, id&#8217;s 4 and 5.  </p>
<p>So what&#8217;s this all mean?  In short, page splits are NOT reversed when a transaction is rolled back.  Why should you care?  Well, you probably wouldn&#8217;t care much, unless you roll back a lot of transactions.  But this is also a good thing to keep in mind if you have to abort a really large insert or update; if you don&#8217;t plan to re-execute the aborted script, you may want to <a href="http://sqlfool.com/2009/03/automated-index-defrag-script/" target="_blank">defrag your indexes</a> to fix the splits.</p>
<p>Source:  <a href="http://sqlfool.com/2009/04/page-splitting-rollbacks/">http://sqlfool.com/2009/04/page-splitting-rollbacks/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sqlfool.com/2009/04/page-splitting-rollbacks/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

