<?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"
	>

<channel>
	<title>Clay Lenhart's Blog</title>
	<atom:link href="http://clay.lenharts.net/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://clay.lenharts.net/blog</link>
	<description>A blog on .Net and SQL Server</description>
	<pubDate>Sat, 14 Jun 2008 12:21:22 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
	<language>en</language>
			<item>
		<title>SQL Server 2005 Compressed Backup</title>
		<link>http://clay.lenharts.net/blog/2008/06/14/sql-server-2005-compressed-backup/</link>
		<comments>http://clay.lenharts.net/blog/2008/06/14/sql-server-2005-compressed-backup/#comments</comments>
		<pubDate>Sat, 14 Jun 2008 12:21:22 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[MSSQL Compressed Backup]]></category>

		<category><![CDATA[SQL Server Administration]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=37</guid>
		<description><![CDATA[I've been working on a way to backup a SQL Server 2005 database to a compressed file recently, but without using temporary files, so I wrote MSSQL Compressed Backup.]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/06/14/sql-server-2005-compressed-backup/&t=SQL Server 2005 Compressed Backup&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I've been working on a way to backup SQL Server 2005 databases to a compressed file recently, but without using temporary files.  I recently found that it is actually pretty easy.  SQL Server has an <a href="http://www.microsoft.com/downloads/details.aspx?familyid=416f8a51-65a3-4e8e-a4c8-adfe15e850fc&amp;displaylang=en">interface for creating a virtual backup device</a> so that the data is pumped to your application, not a real device.  Once the application has the data, it can compress it, encrypt it, or do whatever it likes.  Maybe DBAs would like to save the data to an FTP server.  There are so many options.</p>
<p>The application I wrote is called <a href="http://mssqlcompressed.sourceforge.net/">MSQL Compressed Backup</a> which you can find on Sourceforge.  It is currently in beta, and I don't plan to release a 1.0 version for awhile until it has had some testing by other people.  If you are interested in it, please download a copy and give it a try.</p>
<p>Documentation is currently lacking, but here are a couple of examples.  I think they are self explanatory.</p>
<ul>
<li>msbp.exe backup [model] gzip file:///c:\model.bak.gz</li>
<li>msbp.exe restore file:///c:\model.bak.gz gzip [model]<br />
Here, gzip knows to uncompress since it is in "restore" mode.</li>
<li>msbp.exe backup [model] bzip2(level=5) file:///c:\model.bak.bz2<br />
Each plugin in the pipeline can have parameters.</li>
<li>msbp.exe backup [model] rate(ratemb=5.0) bzip2(level=5) file:///c:\model.bak.bz2<br />
You can have any number of plugins in the pipeline.  The rate plugin limits the impact of a backup on your server by restricting the speed of the backup (or restore).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/06/14/sql-server-2005-compressed-backup/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Influencing the Execution Plan</title>
		<link>http://clay.lenharts.net/blog/2008/04/14/influencing-the-execution-plan/</link>
		<comments>http://clay.lenharts.net/blog/2008/04/14/influencing-the-execution-plan/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 20:37:56 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Development]]></category>

		<category><![CDATA[execution plan]]></category>

		<category><![CDATA[performance]]></category>

		<category><![CDATA[SQL Server Engine]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=36</guid>
		<description><![CDATA[I had a performance problem recently with SQL Server. This post shows an easy relatively hands-off approach to influencing the execution plan.]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/14/influencing-the-execution-plan/&t=Influencing the Execution Plan&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I had a performance problem recently with SQL Server, and I went through the standard <a href="http://www.sql-server-performance.com/articles/per/performance_audit_part6_p1.aspx">performance checklist</a>, however it didn't solve the problem permanently.  Sometimes it would perform well, but most times it was performing poorly.  I knew the next step was to mess with the execution plan.  This is something I really don't like.<span id="more-36"></span></p>
<p>You do not want to force SQL Server to use a particular execution plan, because SQL Server can pick different execution plans depending on how much data will be processed.  When it processes a few rows, it will choose a plan that is optimized for a few rows (and typically use nested loops).  If the same script processes a lot of rows, it will use a plan that is optimized for a lot of rows (and use merge joins or hash joins).  By forcing SQL Server to use single execution plan, you prevent it from using the most efficient execution plan for different scenarios.</p>
<p>But what happens if SQL Server estimates the wrong number of rows?  The worst thing it can do is estimate few rows, use an execution plan optimized for a few rows, and actually process a large number of rows.  In this scenario, you will find a very slow query.</p>
<p>I found an easy fix for this situation.  Use the <a href="http://msdn2.microsoft.com/en-us/library/ms181714.aspx">OPTION</a>(HASH JOIN, MERGE JOIN) modifier to any SELECT, INSERT, UPDATE, or DELETE statement.  For instance:</p>
<pre name="code" class="sql">
UPDATE cust
SET CustomerSourceID = th.SourceID
FROM Customer cust
INNER JOIN TransactionHeader th ON th.CustomerID = cust.CustomerID
WHERE cust.CustomerSourceID IS NULL
OPTION (HASH JOIN, MERGE JOIN)
</pre>
<p>The OPTION (HASH JOIN, MERGE JOIN) modifier does not allow SQL Server to use nested loops.  Since nested loops are typically efficient for a small number of rows, this causes SQL Server to optimize your query for a large number of rows.  Even if this query encounters a few rows, the plan will be moderately efficient.</p>
<p>The good thing about OPTION (HASH JOIN, MERGE JOIN) is</p>
<ul>
<li>It does not require a statement to be restructured.</li>
<li>It will not likely introduce any bugs.</li>
</ul>
<p>The bad thing about it is</p>
<ul>
<li>You prevent SQL Server from selecting the best execution plan for all scenarios.  The plan will be optimized for a large number of rows.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/04/14/influencing-the-execution-plan/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Cached Execution Plans in SQL Server</title>
		<link>http://clay.lenharts.net/blog/2008/04/13/cached-execution-plans-in-sql-server/</link>
		<comments>http://clay.lenharts.net/blog/2008/04/13/cached-execution-plans-in-sql-server/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 20:38:04 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Administration]]></category>

		<category><![CDATA[execution plan]]></category>

		<category><![CDATA[performance]]></category>

		<category><![CDATA[SQL Server Engine]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=35</guid>
		<description><![CDATA[This blog entry describes how you can get the SQL Server execution plan of any running statement and display the graphical representation in Enterprise Manager.]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/13/cached-execution-plans-in-sql-server/&t=Cached Execution Plans in SQL Server&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p><em>I have been working on a performance problem recently, so you might see several blog entries with information that help me.  Hopefully they will help you.</em></p>
<p>Getting the SQL Server execution plan from a production can be difficult, since you are not running the code within Enterprise Manager.  You can still get the execution plan of any running statement and display the graphical representation in Enterprise Manager.<span id="more-35"></span></p>
<p>If your script is currently running, you can <a href="http://blogs.technet.com/vipulshah/archive/2007/09/24/notes-taken-during-pass-session-plan-cache-analysis-in-sql-server-2005.aspx">lookup its execution plan</a> in the plan cache.  The steps are:</p>
<ol>
<li>Run a query to get the the plan_handle of currently running code</li>
<li>Lookup the execution plan for the plan_handle.</li>
</ol>
<p>The first query is:</p>
<pre name="code" class="sql">
SELECT
sder.session_id AS [SPID],
sder.sql_handle as [SQL_Handle],
sder.plan_handle as [PLAN_Handle],
sdes.login_name AS [Login],
sd.name AS [DBName],
sder.start_time AS [Start Time],
sder.status AS [Status],
sder.command AS [Command],
sdet.text AS [SQL Text],
sder.percent_complete AS [Pct Cmplt],
sder.estimated_completion_time AS [Est Cmplt Time],
sder.wait_type AS [Wait],
sder.wait_time AS [Wait Time],
sder.last_wait_type AS [Last Wait],
sder.cpu_time AS [CPU Time],
sder.total_elapsed_time AS [Total Elpsd Time],
sder.reads AS [Reads],
sder.writes AS [Writes],
sder.logical_reads AS [Logical Reads]
FROM
sys.dm_exec_Requests sder
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sdet
JOIN sys.dm_exec_sessions sdes on sder.session_id = sdes.session_id
JOIN sys.databases sd on sder.database_id = sd.database_id
WHERE
sder.session_id &lt;&gt; @@SPID and sder.session_id &gt; 50
</pre>
<p>The second query is:</p>
<pre name="code" class="sql">
SELECT * FROM sys.dm_exec_query_plan ( &lt;PLAN_Handle&gt; )
--here &lt;PLAN_Handle&gt; is supplied based on
--the results from the first query.
</pre>
<p>This gives you the XML execution plan that you can copy and paste into notepad, save it with a *.sqlplan extension, and double click on the file to view the graphical version of the execution plan.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/04/13/cached-execution-plans-in-sql-server/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SSAS Beginner&#8217;s Guide: Storage Structure</title>
		<link>http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/</link>
		<comments>http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/#comments</comments>
		<pubDate>Mon, 07 Apr 2008 20:19:31 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SSAS]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/&t=SSAS Beginner&#8217;s Guide: Storage Structure&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p><em>This is a second entry in a series on SQL Server Analysis Services (SSAS). To see the other blog entries on this tutorial, click on the SSAS Beginner’s Guide on the top bar.</em></p>
<p><strong>Relational Databases</strong></p>
<p>Let’s take a quick look at a relational database table of football players:</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_relational.png" alt="" width="398" height="188" /></p>
<p>The table is structured in rows and columns. Note that the column names are fixed – they are not based on the data. This is a difference between relational databases and SSAS databases.</p>
<p>SSAS databases are typically loaded from the relational database to the SSAS database and a copy of the data stored in a different form in the SSAS database. Once the data has been copied, you can delete the relational database (This assumes you are using the default MOLAP option).</p>
<p><strong>2 Dimensional SSAS Databases</strong></p>
<p>SSAS databases are stored in multidimensional structures. Below is an example of an SSAS database with just 2 dimensions. This contains fantasy football points, so the "2" in the first row and first column is the fantasy football points that Reina received during the 11/Aug/2007 game week.</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_2D.png" alt="" width="478" height="271" /></p>
<p>The grey area contains two dimensions: Players and Game Weeks. Each column header (and row label) is called a <strong>dimension member</strong>. Example dimension members are "Carragher" and "03/11/2007". These dimension members are similar to column names, however they are based on data.</p>
<p>Each number in a cell is at the <strong>intersection</strong> of two dimension members. Take for instance Gerrard’s first match where he received 10 points. It is stored at the intersection of</p>
<ul>
<li>"Gerrard"</li>
<li>and "11/08/2007"</li>
</ul>
<p>Gerrard and "11/08/2007" are <strong>coordinates</strong> to the cell containing 10. When you start writing MDX queries, you will try to find ways to reference these cells using coordinates.</p>
<p>The <strong>All Member</strong> aggregation is what is really useful in SSAS databases. It is a member that is added to each dimension when loading the data. The All Member cells are pre-calculated when loading the SSAS database data and are typically a sum. This member is physically stored and you can also query All Members just like any other member. The All Member aggregation above makes it easy to answer questions like, "What is the total number of points that Gerrard received?" The answer is found at the intersection of</p>
<ul>
<li>"Gerrard"</li>
<li>And the Game Week’s "All Member".</li>
</ul>
<p>You can reference the All Members using the coordinate system just like any other member of the dimension.</p>
<p><strong>3 Dimensional SSAS Database</strong></p>
<p>Let’s take a look at a 3 dimensional SSAS database:</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_3D.png" alt="" width="540" height="332" /></p>
<p>The diagram above shows most of the values stored in the 3 dimensional SSAS database. There are some values in the back of the cube that you can’t see without cutting the cube open, but they still exist.</p>
<p>The cube is shown so that the front pane is the same data as the two dimensional SSAS database above.</p>
<p>Just as a side note, although the diagram has two 10s on the cell for Gerrard on 11/08/2007, on the front in grey and on the top of the cell in white, the cell block itself only contains the number once. The cells can only contain one number and the numbers shown are for the 3D block, rather than a 2D pane. So the cell <img src="http://clay.lenharts.net/blog/images/ssasstorage_3D_onecell.png" alt="" width="124" height="55" /> contains just 17, even though 17 is shown three times.</p>
<p>The only difference with 3D cubes is that locating a cell requires 3 coordinates instead of 2:</p>
<ul>
<li>Game week</li>
<li>Player</li>
<li>Home/Away</li>
</ul>
<p>The 3<sup>rd</sup> dimension, Home/Away, gives us more information about the scores compared to the 2 dimensional database. If you wanted to know how many points these players received for all Away matches, you would go to the intersection of these three coordinates:</p>
<ul>
<li>Game week’s "All Member"</li>
<li>Player’s "All Member"</li>
<li>and Home/Away’s "Away" member</li>
</ul>
<p>Here you will find the value "155".</p>
<p>The cube can answer other questions. Although you cannot see it in the diagram, the cube stores total points that Gerrard received at home. You would find it at the intersection of</p>
<ul>
<li>the game week’s "All Member"</li>
<li>"Gerrard"</li>
<li>"Home".</li>
</ul>
<p>This value would be found on the bottom plane just to the left of the value 155.</p>
<p><strong>4 or More Dimensions</strong></p>
<p>There is really no limit to the number of dimensions you can create in your database even though it might be difficult to visualize. Let’s say you want to track sales for the following:</p>
<ul>
<li>the year 2007</li>
<li>the southeast region</li>
<li>the product "gizmo"</li>
<li>and the "Acme" store</li>
</ul>
<p>You may not be able to see how all the data is stored, however this scenario does have 4 dimensions.</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/&t=SSAS Beginner&#8217;s Guide: Storage Structure&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p><em>This is a second entry in a series on SQL Server Analysis Services (SSAS). To see the other blog entries on this tutorial, click on the SSAS Beginner’s Guide on the top bar.</em></p>
<p><strong>Relational Databases</strong></p>
<p>Let’s take a quick look at a relational database table of football players:</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_relational.png" alt="" width="398" height="188" /></p>
<p>The table is structured in rows and columns. Note that the column names are fixed – they are not based on the data. This is a difference between relational databases and SSAS databases.</p>
<p>SSAS databases are typically loaded from the relational database to the SSAS database and a copy of the data stored in a different form in the SSAS database. Once the data has been copied, you can delete the relational database (This assumes you are using the default MOLAP option).</p>
<p><strong>2 Dimensional SSAS Databases</strong></p>
<p>SSAS databases are stored in multidimensional structures. Below is an example of an SSAS database with just 2 dimensions. This contains fantasy football points, so the "2" in the first row and first column is the fantasy football points that Reina received during the 11/Aug/2007 game week.</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_2D.png" alt="" width="478" height="271" /></p>
<p>The grey area contains two dimensions: Players and Game Weeks. Each column header (and row label) is called a <strong>dimension member</strong>. Example dimension members are "Carragher" and "03/11/2007". These dimension members are similar to column names, however they are based on data.</p>
<p>Each number in a cell is at the <strong>intersection</strong> of two dimension members. Take for instance Gerrard’s first match where he received 10 points. It is stored at the intersection of</p>
<ul>
<li>"Gerrard"</li>
<li>and "11/08/2007"</li>
</ul>
<p>Gerrard and "11/08/2007" are <strong>coordinates</strong> to the cell containing 10. When you start writing MDX queries, you will try to find ways to reference these cells using coordinates.</p>
<p>The <strong>All Member</strong> aggregation is what is really useful in SSAS databases. It is a member that is added to each dimension when loading the data. The All Member cells are pre-calculated when loading the SSAS database data and are typically a sum. This member is physically stored and you can also query All Members just like any other member. The All Member aggregation above makes it easy to answer questions like, "What is the total number of points that Gerrard received?" The answer is found at the intersection of</p>
<ul>
<li>"Gerrard"</li>
<li>And the Game Week’s "All Member".</li>
</ul>
<p>You can reference the All Members using the coordinate system just like any other member of the dimension.</p>
<p><strong>3 Dimensional SSAS Database</strong></p>
<p>Let’s take a look at a 3 dimensional SSAS database:</p>
<p><img src="http://clay.lenharts.net/blog/images/ssasstorage_3D.png" alt="" width="540" height="332" /></p>
<p>The diagram above shows most of the values stored in the 3 dimensional SSAS database. There are some values in the back of the cube that you can’t see without cutting the cube open, but they still exist.</p>
<p>The cube is shown so that the front pane is the same data as the two dimensional SSAS database above.</p>
<p>Just as a side note, although the diagram has two 10s on the cell for Gerrard on 11/08/2007, on the front in grey and on the top of the cell in white, the cell block itself only contains the number once. The cells can only contain one number and the numbers shown are for the 3D block, rather than a 2D pane. So the cell <img src="http://clay.lenharts.net/blog/images/ssasstorage_3D_onecell.png" alt="" width="124" height="55" /> contains just 17, even though 17 is shown three times.</p>
<p>The only difference with 3D cubes is that locating a cell requires 3 coordinates instead of 2:</p>
<ul>
<li>Game week</li>
<li>Player</li>
<li>Home/Away</li>
</ul>
<p>The 3<sup>rd</sup> dimension, Home/Away, gives us more information about the scores compared to the 2 dimensional database. If you wanted to know how many points these players received for all Away matches, you would go to the intersection of these three coordinates:</p>
<ul>
<li>Game week’s "All Member"</li>
<li>Player’s "All Member"</li>
<li>and Home/Away’s "Away" member</li>
</ul>
<p>Here you will find the value "155".</p>
<p>The cube can answer other questions. Although you cannot see it in the diagram, the cube stores total points that Gerrard received at home. You would find it at the intersection of</p>
<ul>
<li>the game week’s "All Member"</li>
<li>"Gerrard"</li>
<li>"Home".</li>
</ul>
<p>This value would be found on the bottom plane just to the left of the value 155.</p>
<p><strong>4 or More Dimensions</strong></p>
<p>There is really no limit to the number of dimensions you can create in your database even though it might be difficult to visualize. Let’s say you want to track sales for the following:</p>
<ul>
<li>the year 2007</li>
<li>the southeast region</li>
<li>the product "gizmo"</li>
<li>and the "Acme" store</li>
</ul>
<p>You may not be able to see how all the data is stored, however this scenario does have 4 dimensions.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/04/07/ssas-beginners-guide-storage-structure/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SQL Server Analysis Services (SSAS) Series</title>
		<link>http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/</link>
		<comments>http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/#comments</comments>
		<pubDate>Tue, 01 Apr 2008 12:34:55 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SSAS]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/&t=SQL Server Analysis Services (SSAS) Series&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I am going to use this blog to convince a friend to use SQL Server Analysis Services (SSAS) in his projects because it makes it easier to write reports on as compared to relational databases.  Part of the challenge is that people don't realize its advantages, and part is the large learning curve to use it.</p>
<p>This first post is on it advantages.  Next will be a whole series to make it a bit easier to learn. First there are two main advantages for using SSAS.</p>
<p><strong>SSAS is fast even on a large volume of data</strong></p>
<p>Well, as long as the queries return few rows, and this really gets at the heart of when you want to use SSAS and when you don't.  It is good at returning a single sum for a column over a large number of rows, but is very slow at returning a lot of detailed rows.  The reason for this is the totals (and the subtotals) are stored in the SSAS database.  It takes more work to read all the original rows than the one single subtotal value.  In fact, relational databases will be faster at returning detailed rows compared to SSAS.</p>
<p>Take for example the following SQL code from a relational database:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> SUM<span style="color: #66cc66;">&#40;</span>Cost<span style="color: #66cc66;">&#41;</span><span style="color: #993333; font-weight: bold;">FROM</span> Sales</pre>
<p>In SQL Server, this query could take a very long time as it scans the Sales table, however in SSAS the result comes back instantly because the one value is already pre-calculated and stored in the SSAS database.</p>
<p><strong>SSAS's calculated measures are fast execution-wise and easy reusable</strong></p>
<p>In relational databases, calculation code can get messy. The main problem with SQL SELECT statements is that they make it difficult to write a calculation once, like in a function, and GROUP BY different ways.  You might build a SELECT statement in a string and execute the string using sp_executesql, or you use a CASE statement to list the different SELECT statements that group differently. Both are messy compared to SSAS.</p>
<p>Calculated measures in SSAS give you a way to define the calculations in a straight forward manner that does not matter how you will group the data later.  They also you another advantage in that they are defined centrally in the SSAS database, and the reports pick and choose the calculated measures they want.  This moves formulas from many reports to the central SSAS database where they are tested once.</p>
<p>Between having one set of centralized "official" formulas, and having formulas written in clear straight forward manner, the reports will have fewer number of bugs.</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/&t=SQL Server Analysis Services (SSAS) Series&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I am going to use this blog to convince a friend to use SQL Server Analysis Services (SSAS) in his projects because it makes it easier to write reports on as compared to relational databases.  Part of the challenge is that people don't realize its advantages, and part is the large learning curve to use it.</p>
<p>This first post is on it advantages.  Next will be a whole series to make it a bit easier to learn. First there are two main advantages for using SSAS.</p>
<p><strong>SSAS is fast even on a large volume of data</strong></p>
<p>Well, as long as the queries return few rows, and this really gets at the heart of when you want to use SSAS and when you don't.  It is good at returning a single sum for a column over a large number of rows, but is very slow at returning a lot of detailed rows.  The reason for this is the totals (and the subtotals) are stored in the SSAS database.  It takes more work to read all the original rows than the one single subtotal value.  In fact, relational databases will be faster at returning detailed rows compared to SSAS.</p>
<p>Take for example the following SQL code from a relational database:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> SUM<span style="color: #66cc66;">&#40;</span>Cost<span style="color: #66cc66;">&#41;</span><span style="color: #993333; font-weight: bold;">FROM</span> Sales</pre>
<p>In SQL Server, this query could take a very long time as it scans the Sales table, however in SSAS the result comes back instantly because the one value is already pre-calculated and stored in the SSAS database.</p>
<p><strong>SSAS's calculated measures are fast execution-wise and easy reusable</strong></p>
<p>In relational databases, calculation code can get messy. The main problem with SQL SELECT statements is that they make it difficult to write a calculation once, like in a function, and GROUP BY different ways.  You might build a SELECT statement in a string and execute the string using sp_executesql, or you use a CASE statement to list the different SELECT statements that group differently. Both are messy compared to SSAS.</p>
<p>Calculated measures in SSAS give you a way to define the calculations in a straight forward manner that does not matter how you will group the data later.  They also you another advantage in that they are defined centrally in the SSAS database, and the reports pick and choose the calculated measures they want.  This moves formulas from many reports to the central SSAS database where they are tested once.</p>
<p>Between having one set of centralized "official" formulas, and having formulas written in clear straight forward manner, the reports will have fewer number of bugs.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/04/01/sql-server-analysis-services-ssas-series/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Table Size Query</title>
		<link>http://clay.lenharts.net/blog/2008/03/08/table-size-query/</link>
		<comments>http://clay.lenharts.net/blog/2008/03/08/table-size-query/#comments</comments>
		<pubDate>Sat, 08 Mar 2008 00:13:59 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Administration]]></category>

		<category><![CDATA[dynamic management views]]></category>

		<category><![CDATA[SQL Server Engine]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/03/08/table-size-query/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/03/08/table-size-query/&t=Table Size Query&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>The following query lists the tables and the space they use. This query is much faster (sub-second) than a standard SELECT COUNT(*) query since it uses the dynamic management views in SQL Server rather than scanning your data.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> sum <span style="color: #66cc66;">&#40;</span> used_page_count <span style="color: #66cc66;">&#41;</span> * <span style="color: #cc66cc;">8</span> <span style="color: #993333; font-weight: bold;">AS</span> SizeKB,
  sum<span style="color: #66cc66;">&#40;</span>row_count<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #66cc66;">&#91;</span>RowCount<span style="color: #66cc66;">&#93;</span>, object_name <span style="color: #66cc66;">&#40;</span> object_id <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> TableName
<span style="color: #993333; font-weight: bold;">FROM</span> sys.dm_db_partition_stats
<span style="color: #993333; font-weight: bold;">WHERE</span> index_id=<span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">OR</span> index_id=<span style="color: #cc66cc;">1</span>
<span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> object_id
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> sum <span style="color: #66cc66;">&#40;</span> used_page_count <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DESC</span>;</pre>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/03/08/table-size-query/&t=Table Size Query&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>The following query lists the tables and the space they use. This query is much faster (sub-second) than a standard SELECT COUNT(*) query since it uses the dynamic management views in SQL Server rather than scanning your data.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> sum <span style="color: #66cc66;">&#40;</span> used_page_count <span style="color: #66cc66;">&#41;</span> * <span style="color: #cc66cc;">8</span> <span style="color: #993333; font-weight: bold;">AS</span> SizeKB,
  sum<span style="color: #66cc66;">&#40;</span>row_count<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #66cc66;">&#91;</span>RowCount<span style="color: #66cc66;">&#93;</span>, object_name <span style="color: #66cc66;">&#40;</span> object_id <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> TableName
<span style="color: #993333; font-weight: bold;">FROM</span> sys.dm_db_partition_stats
<span style="color: #993333; font-weight: bold;">WHERE</span> index_id=<span style="color: #cc66cc;">0</span> <span style="color: #993333; font-weight: bold;">OR</span> index_id=<span style="color: #cc66cc;">1</span>
<span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> object_id
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> sum <span style="color: #66cc66;">&#40;</span> used_page_count <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DESC</span>;</pre>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/03/08/table-size-query/feed/</wfw:commentRss>
		</item>
		<item>
		<title>HierarchyID in SQL Server 2008</title>
		<link>http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/</link>
		<comments>http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/#comments</comments>
		<pubDate>Sat, 23 Feb 2008 20:04:58 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Development]]></category>

		<category><![CDATA[SQL Server 2008]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/&t=HierarchyID in SQL Server 2008&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>SQL Server 2008 includes a new <a href="http://www.sql-server-performance.com/articles/dev/new_data_types_sql_server-2008_p1.aspx">HierarchyID datatype</a>!</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/&t=HierarchyID in SQL Server 2008&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>SQL Server 2008 includes a new <a href="http://www.sql-server-performance.com/articles/dev/new_data_types_sql_server-2008_p1.aspx">HierarchyID datatype</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/02/23/hierarchyid-in-sql-server-2008/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Advantages of Immutable Data</title>
		<link>http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/</link>
		<comments>http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/#comments</comments>
		<pubDate>Sat, 16 Feb 2008 19:44:01 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[Architecture]]></category>

		<category><![CDATA[Immutable]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/&t=Advantages of Immutable Data&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I was reading about two of Google's internal programs, <a href="http://www.usenix.org/events/osdi06/tech/chang/chang_html/index.html">Bigtable</a> and <a href="http://labs.google.com/papers/gfs.html">Google File System</a>, and how they handle a large amounts of data so that the processing is distributed (Bigtable) and the data is replicated (Google File System).  One thing they both do is exploit immutability.  So once something is saved to disk, that block of data doesn't change.  If you have a large volume of data, this assumption can be very useful.</p>
<p>Let's say we're talking about a transaction table for bank accounts. Records in the transaction table don't change.  Any corrections are handled by creating a new transaction record at the tail end of the table.  If you are processing the transactions, this is great! You can ignore previously processed records since you know they will never change.</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/&t=Advantages of Immutable Data&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>I was reading about two of Google's internal programs, <a href="http://www.usenix.org/events/osdi06/tech/chang/chang_html/index.html">Bigtable</a> and <a href="http://labs.google.com/papers/gfs.html">Google File System</a>, and how they handle a large amounts of data so that the processing is distributed (Bigtable) and the data is replicated (Google File System).  One thing they both do is exploit immutability.  So once something is saved to disk, that block of data doesn't change.  If you have a large volume of data, this assumption can be very useful.</p>
<p>Let's say we're talking about a transaction table for bank accounts. Records in the transaction table don't change.  Any corrections are handled by creating a new transaction record at the tail end of the table.  If you are processing the transactions, this is great! You can ignore previously processed records since you know they will never change.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/02/16/advantages-of-immutable-data/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SQL Server Hash Indexes</title>
		<link>http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/</link>
		<comments>http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/#comments</comments>
		<pubDate>Sun, 03 Feb 2008 13:27:04 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/&t=SQL Server Hash Indexes&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>There are two problems with indexes on large nvarchar columns:</p>
<ul>
<li>You will likely hit the 900 byte limit in your index</li>
<li>Indexing large data isn't efficient anyway.</li>
</ul>
<p>A neat feature of SQL Server is the CHECKSUM() function which hashes your varchar/nvarchar values into a 4 byte number.  You can then use this value in an index.  For example if you have a Site table, add a calculated column, URLChecksum.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> Site <span style="color: #66cc66;">&#40;</span>
  SiteID int <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  URL nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2083</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  URLChecksum <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #66cc66;">&#40;</span>checksum<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>URL<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>,
 CONSTRAINT <span style="color: #66cc66;">&#91;</span>PK_Site<span style="color: #66cc66;">&#93;</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> CLUSTERED <span style="color: #66cc66;">&#40;</span>SiteID<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre>
<p>Next create an index on the hash and include the URL:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> IX_Site <span style="color: #993333; font-weight: bold;">ON</span> Site <span style="color: #66cc66;">&#40;</span>URLChecksum<span style="color: #66cc66;">&#41;</span> INCLUDE <span style="color: #66cc66;">&#40;</span>URL<span style="color: #66cc66;">&#41;</span>;</pre>
<p>This index will make the following query faster:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> SiteID
<span style="color: #993333; font-weight: bold;">FROM</span> Site
<span style="color: #993333; font-weight: bold;">WHERE</span> URLChecksum = CHECKSUM<span style="color: #66cc66;">&#40;</span>N<span style="color: #ff0000;">'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;amp;displaylang=en'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">AND</span> URL = N<span style="color: #ff0000;">'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;amp;displaylang=en'</span>;</pre>
<p>This query will first "seek" the hash value in the index very quickly, since the hash values are just ints.  Once it finds one or more matching hash values, it will check that the URLs match.  Since the URLChecksum, URL, and SiteID values are included in the index, this query does not need to touch the Site table.</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/&t=SQL Server Hash Indexes&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>There are two problems with indexes on large nvarchar columns:</p>
<ul>
<li>You will likely hit the 900 byte limit in your index</li>
<li>Indexing large data isn't efficient anyway.</li>
</ul>
<p>A neat feature of SQL Server is the CHECKSUM() function which hashes your varchar/nvarchar values into a 4 byte number.  You can then use this value in an index.  For example if you have a Site table, add a calculated column, URLChecksum.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> Site <span style="color: #66cc66;">&#40;</span>
  SiteID int <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  URL nvarchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2083</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  URLChecksum <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #66cc66;">&#40;</span>checksum<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#91;</span>URL<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>,
 CONSTRAINT <span style="color: #66cc66;">&#91;</span>PK_Site<span style="color: #66cc66;">&#93;</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> CLUSTERED <span style="color: #66cc66;">&#40;</span>SiteID<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre>
<p>Next create an index on the hash and include the URL:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> IX_Site <span style="color: #993333; font-weight: bold;">ON</span> Site <span style="color: #66cc66;">&#40;</span>URLChecksum<span style="color: #66cc66;">&#41;</span> INCLUDE <span style="color: #66cc66;">&#40;</span>URL<span style="color: #66cc66;">&#41;</span>;</pre>
<p>This index will make the following query faster:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> SiteID
<span style="color: #993333; font-weight: bold;">FROM</span> Site
<span style="color: #993333; font-weight: bold;">WHERE</span> URLChecksum = CHECKSUM<span style="color: #66cc66;">&#40;</span>N<span style="color: #ff0000;">'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;amp;displaylang=en'</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">AND</span> URL = N<span style="color: #ff0000;">'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;amp;displaylang=en'</span>;</pre>
<p>This query will first "seek" the hash value in the index very quickly, since the hash values are just ints.  Once it finds one or more matching hash values, it will check that the URLs match.  Since the URLChecksum, URL, and SiteID values are included in the index, this query does not need to touch the Site table.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;Including&#8221; Columns in an Index</title>
		<link>http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/</link>
		<comments>http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/#comments</comments>
		<pubDate>Sat, 02 Feb 2008 16:08:25 +0000</pubDate>
		<dc:creator>Clay Lenhart</dc:creator>
		
		<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/</guid>
		<description><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/&t=&#8220;Including&#8221; Columns in an Index&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>A neat feature in SQL Server 2005 is the ability to "include" columns in an index.  These included columns are not in the main part of the index, but are additional information in the index.</p>
<p>For example, lets say you have the following SELECT statement:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> Url
&nbsp;
<span style="color: #993333; font-weight: bold;">FROM</span> Site
&nbsp;
<span style="color: #993333; font-weight: bold;">WHERE</span> Category = <span style="color: #ff0000;">'News'</span>;</pre>
<p>You might be tempted to create a covering index with Category as the first column, and Url as the second column. Since URLs can be 2083 characters, you can't put the URL column in an index since it would exceed 900 bytes.  However, the query above would benefit from the following index where the URL is "included" in the index and therefore isn't restricted to 900 bytes.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> IX_Site <span style="color: #993333; font-weight: bold;">ON</span> dbo.Site <span style="color: #66cc66;">&#40;</span>Category<span style="color: #66cc66;">&#41;</span> INCLUDE <span style="color: #66cc66;">&#40;</span>Url<span style="color: #66cc66;">&#41;</span>;</pre>
<p>The main part of the index only contains the category column.  The index also stores the Url, but the Url can't be efficiently used for filtering.  In the SELECT statement above, this is OK, since the Url is only returned, not filtered.</p>
<p>Another benefit is that the main part of the index is smaller, so it is faster to find records in the index.</p>
]]></description>
			<content:encoded><![CDATA[<div class="diggthisplugin" style="float: right; width: 42px; padding-right: 10px; margin-left: 10px; margin-bottom: 0px;"><iframe src="http://digg.com/tools/diggthis.php?u=http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/&t=&#8220;Including&#8221; Columns in an Index&k=#FFFFFF" scrolling="no" style="border: none; height: 80px; width: 52px;"></iframe>
		</div><p>A neat feature in SQL Server 2005 is the ability to "include" columns in an index.  These included columns are not in the main part of the index, but are additional information in the index.</p>
<p>For example, lets say you have the following SELECT statement:</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> Url
&nbsp;
<span style="color: #993333; font-weight: bold;">FROM</span> Site
&nbsp;
<span style="color: #993333; font-weight: bold;">WHERE</span> Category = <span style="color: #ff0000;">'News'</span>;</pre>
<p>You might be tempted to create a covering index with Category as the first column, and Url as the second column. Since URLs can be 2083 characters, you can't put the URL column in an index since it would exceed 900 bytes.  However, the query above would benefit from the following index where the URL is "included" in the index and therefore isn't restricted to 900 bytes.</p>
<pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> IX_Site <span style="color: #993333; font-weight: bold;">ON</span> dbo.Site <span style="color: #66cc66;">&#40;</span>Category<span style="color: #66cc66;">&#41;</span> INCLUDE <span style="color: #66cc66;">&#40;</span>Url<span style="color: #66cc66;">&#41;</span>;</pre>
<p>The main part of the index only contains the category column.  The index also stores the Url, but the Url can't be efficiently used for filtering.  In the SELECT statement above, this is OK, since the Url is only returned, not filtered.</p>
<p>Another benefit is that the main part of the index is smaller, so it is faster to find records in the index.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
