<?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>Clay Lenhart's Blog &#187; SQL Server Development</title>
	<atom:link href="http://clay.lenharts.net/blog/category/sql-server-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://clay.lenharts.net/blog</link>
	<description>A blog on .Net and SQL Server</description>
	<lastBuildDate>Tue, 31 Oct 2017 10:34:08 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.2.2</generator>
	<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><![CDATA[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. <a href="http://clay.lenharts.net/blog/2008/04/14/influencing-the-execution-plan/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<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&#8217;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&#8217;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 class="brush: sql; title: ; notranslate">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>
		<slash:comments>10</slash:comments>
		</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><![CDATA[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[SQL Server 2008 includes a new HierarchyID datatype!]]></description>
				<content:encoded><![CDATA[<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>
		<slash:comments>5</slash:comments>
		</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><![CDATA[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[There are two problems with indexes on large nvarchar columns: You will likely hit the 900 byte limit in your index Indexing large data isn&#8217;t efficient anyway. A neat feature of SQL Server is the CHECKSUM() function which hashes your &#8230; <a href="http://clay.lenharts.net/blog/2008/02/03/sql-server-hash-indexes/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<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&#8217;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 lang="sql">CREATE TABLE Site (
  SiteID int NOT NULL,
  URL nvarchar(2083) NOT NULL,
  URLChecksum AS (checksum([URL])),
 CONSTRAINT [PK_Site] PRIMARY KEY CLUSTERED (SiteID)
);</pre>
<p>Next create an index on the hash and include the URL:</p>
<pre lang="sql">CREATE INDEX IX_Site ON Site (URLChecksum) INCLUDE (URL);</pre>
<p>This index will make the following query faster:</p>
<pre lang="sql">SELECT SiteID
FROM Site
WHERE URLChecksum = CHECKSUM(N'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;displaylang=en')
AND URL = N'http://www.microsoft.com/downloads/details.aspx?familyid=9a8b005b-84e4-4f24-8d65-cb53442d9e19&amp;displaylang=en';</pre>
<p>This query will first &#8220;seek&#8221; 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>
		<slash:comments>7</slash:comments>
		</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><![CDATA[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[A neat feature in SQL Server 2005 is the ability to &#8220;include&#8221; columns in an index. These included columns are not in the main part of the index, but are additional information in the index. For example, lets say you &#8230; <a href="http://clay.lenharts.net/blog/2008/02/02/including-columns-in-an-index/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A neat feature in SQL Server 2005 is the ability to &#8220;include&#8221; 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 lang="sql">SELECT Url

FROM Site

WHERE Category = 'News';</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&#8217;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 &#8220;included&#8221; in the index and therefore isn&#8217;t restricted to 900 bytes.</p>
<pre lang="sql">CREATE INDEX IX_Site ON dbo.Site (Category) INCLUDE (Url);</pre>
<p>The main part of the index only contains the category column.  The index also stores the Url, but the Url can&#8217;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>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The sp_getapplock secret</title>
		<link>http://clay.lenharts.net/blog/2008/01/28/the-sp_getapplock-secret/</link>
		<comments>http://clay.lenharts.net/blog/2008/01/28/the-sp_getapplock-secret/#comments</comments>
		<pubDate>Mon, 28 Jan 2008 21:39:59 +0000</pubDate>
		<dc:creator><![CDATA[Clay Lenhart]]></dc:creator>
				<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/01/28/the-sp_getapplock-secret/</guid>
		<description><![CDATA[sp_getapplock is not very well advertised in SQL Server 2005, however it is a good way to synchronize code in a stored procedure. Before finding out about sp_getapplock, I would SELECT from a table with an exclusive lock, like so: &#8230; <a href="http://clay.lenharts.net/blog/2008/01/28/the-sp_getapplock-secret/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>sp_getapplock is not very well advertised in SQL Server 2005, however it is a good way to synchronize code in a stored procedure.</p>
<p>Before finding out about  sp_getapplock, I would SELECT from a table with an exclusive lock, like so:</p>
<pre class="brush: sql; title: ; notranslate">
BEGIN TRAN;
SELECT TOP 1 * FROM dbo.ATable with (tablockx, holdlock);
-- Do something while the lock is held, for instance:
UPDATE dbo.ATable SET FieldA = FieldA + 1 WHERE FieldB = 'something';
COMMIT TRAN;
</pre>
<p>This blocks other users from entering the section of code until the lock is released (when the transaction is committed).  Normally you couldn&#8217;t do FieldA = FieldA + 1, because other users might be updating the table, however with the lock on the table you could.</p>
<p>This approach has some downsides</p>
<ol>
<li>Other users can&#8217;t SELECT from the table.</li>
<li>If you rebuild indexes on the table with the &#8220;online=on&#8221; option, it will want to put a schema lock on the table, to prevent other schema changes.  The exclusive lock prevents the rebuild from starting.</li>
</ol>
<p>sp_getapplock is the built-in way to allow only one user in a section of code at a time, for example:</p>
<pre class="brush: sql; title: ; notranslate">BEGIN TRANSACTION
DECLARE @res INT
EXEC @res = sp_getapplock @Resource = 'Lock ID', @LockMode = 'Exclusive';
IF @res &gt;= 0
BEGIN
PRINT 'lock is held.';
END
COMMIT TRAN;
</pre>
<p>@Resource can be used for different locks that don&#8217;t interfere with each other.</p>
<p>You have to be careful which database you are &#8220;use&#8221;ing.  SQL Server assumes that different databases have nothing to do with each other and won&#8217;t block each other.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/01/28/the-sp_getapplock-secret/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>SQL Server Security with EXECUTE AS OWNER</title>
		<link>http://clay.lenharts.net/blog/2008/01/24/sql-server-security-with-execute-as-owner/</link>
		<comments>http://clay.lenharts.net/blog/2008/01/24/sql-server-security-with-execute-as-owner/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 21:54:16 +0000</pubDate>
		<dc:creator><![CDATA[Clay Lenhart]]></dc:creator>
				<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/2008/01/24/sql-server-security-with-execute-as-owner/</guid>
		<description><![CDATA[EXECUTE AS OWNER is a great way to limit the permissions of a SQL Server Login. The general idea is to create your stored procedure with the EXECUTE AS OWNER modifier. Any user who has the permissions to execute the &#8230; <a href="http://clay.lenharts.net/blog/2008/01/24/sql-server-security-with-execute-as-owner/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>EXECUTE AS OWNER is a great way to limit the permissions of a SQL Server Login.  The general idea is to create your stored procedure with the EXECUTE AS OWNER modifier.   Any user who has the permissions to execute the stored procedure, runs the stored procedure under the Database&#8217;s dbo user (which means it can do anything in the database, but nothing at the server-level nor on other databases). If you only allow your Logins to execute stored procedures (and not touch the tables directly), then you&#8217;ve effectively limited the Logins to code you&#8217;ve written.  If you don&#8217;t write any DELETE statements, then Logins can&#8217;t delete anything.</p>
<p>This is better than Roles, because Roles are very coarse in comparison.  With Roles, you may have to give a User INSERT permissions on table.  Instead with EXECUTE AS OWNER you can write a stored procedure that checks the data exactly the way you want in the body of the stored procedure.  This is much more fine grained way of handling permissions.</p>
<p>From beginning to end, this is what you do:</p>
<p>Create a Login:<br />
<code> </code></p>
<pre lang="sql">CREATE LOGIN [MyLogin] WITH PASSWORD=N'Password',
DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;</pre>
<p>Create its User in the database:</p>
<pre lang="sql">CREATE USER [MyUser] FOR LOGIN [MyLogin];</pre>
<p>I prefer to use schemas to identify &#8220;public&#8221; stored procedures.  So create a schema:</p>
<pre lang="sql">CREATE SCHEMA [public] AUTHORIZATION [dbo];</pre>
<p>Give your new user EXECUTE permissions on anything in the public schema: (We will put the new stored procedure in this schema):</p>
<pre lang="sql">GRANT EXECUTE ON SCHEMA::[public] TO [MyUser];</pre>
<p>Create your stored procedure:</p>
<pre lang="sql">CREATE PROCEDURE [public].[MyStoredProc]
(
@Param1 int
)
WITH EXECUTE AS OWNER   -- This "EXECUTE AS" modifier on the stored procedure is key!
AS
BEGIN
SET NOCOUNT ON;

-- do something

END</pre>
<p>When your stored procedure runs, it can do anything in the database, including calling other stored procedures.  It is an easy way to segregate public stored procedures from private ones.  This gives you encapsulation, which is a good thing (see section 5.3 in <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670">Code Complete</a> about the benefits of encapsulation).</p>
<p>The only permissions outside users need is EXECUTE permission on the public schema, so it is easy to add new stored procedures by creating them in the public schema.</p>
<p>Instead of Roles, you can have schemas.  Let&#8217;s say you would have 3 roles in the database: admin, anon, and general.  The admin role is for Logins that perform administrative activity on a website.  The anon role is for people who view your site anonymously, and the general role is for stored procedures that are for both.  You can instead, with EXECUTE AS OWNER, create three schemas for your stored procedures: admin, anon, and general.  If you want the stored procedure to have admin only Logins to use it, create the stored procedure in the admin schema.  The same goes for the other schemas.</p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2008/01/24/sql-server-security-with-execute-as-owner/feed/</wfw:commentRss>
		<slash:comments>56</slash:comments>
		</item>
		<item>
		<title>Natural Keys vs Surrogate Keys</title>
		<link>http://clay.lenharts.net/blog/2007/12/10/natural-keys-vs-surrogate-keys/</link>
		<comments>http://clay.lenharts.net/blog/2007/12/10/natural-keys-vs-surrogate-keys/#comments</comments>
		<pubDate>Mon, 10 Dec 2007 21:36:44 +0000</pubDate>
		<dc:creator><![CDATA[Clay Lenhart]]></dc:creator>
				<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=10</guid>
		<description><![CDATA[This blog entry has a good description of the pros (and some cons) of surrogate keys: http://rapidapplicationdevelopment.blogspot.com/2007/08/in-case-youre-new-to-series-ive.html]]></description>
				<content:encoded><![CDATA[<p> This blog entry has a good description of the pros (and some cons) of surrogate keys:</p>
<p><a href="http://rapidapplicationdevelopment.blogspot.com/2007/08/in-case-youre-new-to-series-ive.html">http://rapidapplicationdevelopment.blogspot.com/2007/08/in-case-youre-new-to-series-ive.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2007/12/10/natural-keys-vs-surrogate-keys/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Sorting uniqueidentifiers in SQL Server 2005</title>
		<link>http://clay.lenharts.net/blog/2007/11/20/sorting-uniqueidentifiers-in-sql-server-2005/</link>
		<comments>http://clay.lenharts.net/blog/2007/11/20/sorting-uniqueidentifiers-in-sql-server-2005/#comments</comments>
		<pubDate>Tue, 20 Nov 2007 22:15:24 +0000</pubDate>
		<dc:creator><![CDATA[Clay Lenhart]]></dc:creator>
				<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=5</guid>
		<description><![CDATA[I had an issue recently where I needed to sort on a uniqueidentifier column and read the data in .Net. I found that .Net sorts Guids differently than SQL Server. You can see for yourself. Run the following code. DECLARE &#8230; <a href="http://clay.lenharts.net/blog/2007/11/20/sorting-uniqueidentifiers-in-sql-server-2005/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I had an issue recently where I needed to sort on a uniqueidentifier column and read the data in .Net.  I found that <strong>.Net sorts Guids differently than SQL Server.</strong></p>
<p>You can see for yourself. <img src="http://clay.lenharts.net/blog/wp-includes/images/smilies/simple-smile.png" alt=":)" class="wp-smiley" style="height: 1em; max-height: 1em;" />  Run the following code.</p>
<pre lang="sql">

DECLARE @t TABLE (
   g uniqueidentifier
); 

INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000001' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000010' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000000100' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000001000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000010000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000000100000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000001000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000010000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-000100000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-001000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-010000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0000-100000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0001-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0010-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-0100-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0000-1000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0001-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0010-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-0100-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0000-1000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0001-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0010-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-0100-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000000-1000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000001-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000010-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00000100-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00001000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00010000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '00100000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '01000000-0000-0000-0000-000000000000' );
INSERT INTO @t ( g ) VALUES ( '10000000-0000-0000-0000-000000000000' ); 

SELECT * FROM @t order by g ;</pre>
<p>It returns the data in the following bizarre order.  Keep in mind the first row is the &#8220;smallest&#8221; number.</p>
<table border="1">
<tr>
<th>g</th>
</tr>
<tr>
<td>01000000-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>10000000-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00010000-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00100000-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000100-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00001000-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000001-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000010-0000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0100-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-1000-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0001-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0010-0000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0100-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-1000-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0001-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0010-0000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0001-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0010-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0100-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-1000-000000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000000001</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000000010</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000000100</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000001000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000010000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000000100000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000001000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000010000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-000100000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-001000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-010000000000</td>
</tr>
<tr>
<td>00000000-0000-0000-0000-100000000000</td>
</tr>
</table>
<p>In the end, I decided to SELECT two bigint columns that indicate how SQL Server is sorting the data.  This is CPU intensive, so it isn&#8217;t ideal, however it shows SQL Server&#8217;s strange sorting behaviour of the uniqueidentifier column.</p>
<pre lang="sql">
CREATE FUNCTION dbo.GuidHigh
(
	@g uniqueidentifier
)
RETURNS bigint
AS
BEGIN

	DECLARE @s varchar(40);
	SET @s = @g;
	-- @s is in the format 3B3A8D04-5D0C-4E0C-AC69-EFC14EE7D849

	SET @s = REPLACE(@s, '-', '');
	-- @s is in the format 3B3A8D045D0C4E0CAC69EFC14EE7D849

	DECLARE @highA varchar(40);
	DECLARE @highB varchar(40);

	SET @highA = SUBSTRING(@s, 21, 12);
	SET @highB = SUBSTRING(@s, 17, 4);

	DECLARE @high varchar(40);
	SET @high = @highA + @highB;

	DECLARE @MinBigInt numeric(21,0);
	SET @MinBigInt = 9223372036854775808;

	RETURN CAST(dbo.[HexStrToNumeric](@high) - @MinBigInt as bigint);

END
GO

CREATE FUNCTION dbo.[GuidLow]
(
	@g uniqueidentifier
)
RETURNS bigint
AS
BEGIN

	DECLARE @s varchar(40);
	SET @s = @g;
	-- @s is in the format 3B3A8D04-5D0C-4E0C-AC69-EFC14EE7D849

	SET @s = REPLACE(@s, '-', '');
	-- @s is in the format 3B3A8D045D0C4E0CAC69EFC14EE7D849

	DECLARE @lowA varchar(40);
	DECLARE @lowB varchar(40);
	DECLARE @lowC varchar(40);
	DECLARE @lowD varchar(40);
	DECLARE @lowE varchar(40);
	DECLARE @lowF varchar(40);
	DECLARE @lowG varchar(40);
	DECLARE @lowH varchar(40);

	SET @lowA = SUBSTRING(@s, 15, 2);
	SET @lowB = SUBSTRING(@s, 13, 2);
	SET @lowC = SUBSTRING(@s, 11, 2);
	SET @lowD = SUBSTRING(@s, 9, 2);
	SET @lowE = SUBSTRING(@s, 7, 2);
	SET @lowF = SUBSTRING(@s, 5, 2);
	SET @lowG = SUBSTRING(@s, 3, 2);
	SET @lowH = SUBSTRING(@s, 1, 2);

	DECLARE @low varchar(40);
	SET @low = @lowA + @lowB + @lowC + @lowD + @lowE + @lowF + @lowG + @lowH;

	DECLARE @MinBigInt numeric(21,0);
	SET @MinBigInt = 9223372036854775808;

	RETURN CAST(dbo.[HexStrToNumeric](@low) - @MinBigInt as bigint);

END
GO

-- do not include "0x" in the parameter, just a string like "8E75EF35FF75A977"

CREATE FUNCTION dbo.[HexStrToNumeric](@hexstr varchar(16))
RETURNS numeric(21, 0) -- enough for 2^64
AS
BEGIN
    DECLARE @hex char(2), @i int, @count int, @result numeric(21, 0), @power numeric(21, 0);
    SET @result = 0;
    SET @count = LEN(@hexstr)
    SET @i = 1
    SET @power = 1;
    WHILE (@i &lt;= @count)
    BEGIN
	SET @power = @power * 16;
        SET @i = @i + 1
    END;

    SET @i = 1
    WHILE (@i &lt;= @count)
    BEGIN
 	SET @power = @power / 16;
        SET @hex = SUBSTRING(@hexstr, @i, 1)
        SET @result = @result + @power *
                CASE WHEN @hex LIKE '[0-9]'
                    THEN CAST(@hex as int)
                    ELSE CAST(ASCII(UPPER(@hex))-55 as int)
                END
        SET @i = @i + 1
    END
    RETURN @result
END
GO</pre>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2007/11/20/sorting-uniqueidentifiers-in-sql-server-2005/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Are Foreign Keys Bad?</title>
		<link>http://clay.lenharts.net/blog/2007/11/17/are-foreign-keys-bad/</link>
		<comments>http://clay.lenharts.net/blog/2007/11/17/are-foreign-keys-bad/#comments</comments>
		<pubDate>Sat, 17 Nov 2007 21:04:11 +0000</pubDate>
		<dc:creator><![CDATA[Clay Lenhart]]></dc:creator>
				<category><![CDATA[SQL Server Development]]></category>

		<guid isPermaLink="false">http://clay.lenharts.net/blog/?p=3</guid>
		<description><![CDATA[The Problem Mike Simpson&#8217;s post on foreign keys raises some good points: http://www.slipjig.org/Mike/post/2007/11/Are-Foreign-Keys-Bad&#8211;You-Decide!.aspx. The main issue raised is how foreign keys cause deadlocks. In order to avoid deadlocks, you have to acquire locks on records in the same order, always. &#8230; <a href="http://clay.lenharts.net/blog/2007/11/17/are-foreign-keys-bad/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><strong>The Problem </strong></p>
<p>Mike Simpson&#8217;s post on foreign keys raises some good points: <a href="http://www.slipjig.org/Mike/post/2007/11/Are-Foreign-Keys-Bad--You-Decide!.aspx">http://www.slipjig.org/Mike/post/2007/11/Are-Foreign-Keys-Bad&#8211;You-Decide!.aspx</a>.  The main issue raised is how foreign keys cause deadlocks.  In order to avoid deadlocks, you have to acquire locks on records in the same order, always.  When you insert and update records related by foreign keys, you lock records from the parent tables to the child tables.  To delete records, you lock records in the opposite order (child to parent tables) due to foreign key constraints, leading to potential deadlocks.</p>
<p><strong>The Usual Solutions </strong></p>
<p>There are three general approaches to deal with deadlocks:</p>
<ul>
<li>Add retry code to handle deadlocks.  Typically this is a lot of work and error prone &#8212; not to mention difficult to test.  You generally don&#8217;t see many developers doing this due to the effort involved.</li>
<li>DELETE in the opposite order and allow deadlocks to occur.  This isn&#8217;t as bad as it seems.  It is common to have a little validation in the database layer &#8212; for instance for &#8220;The username must be unique&#8221; type validation. So you treat the deadlock like a validation error, report it to the user, and let the user hit the Save button again.  Keep in mind that you may have a backend processes that can deadlock, which isn&#8217;t ideal &#8212; these backend processes don&#8217;t have to DELETE in order to deadlock.  Even if it just has INSERTs and UPDATEs, it still can deadlock with a user who is DELETing in the opposite order (or more generally, locking in a different order).</li>
<li>&#8220;Logically delete&#8221; in the same order as INSERTs and UPDATEs to avoid deadlocks.  Logical deletes are really updates where you set a field such as &#8220;IsDeleted&#8221; to true.  The downside to this approach is all your SELECT statements have to filter out the &#8220;deleted&#8221; records, which could be error prone.  The difference between this approach and the first approach though, is that this approach is much easier to test.</li>
</ul>
<p><strong>Don&#8217;t Use Foreign Keys!?!? </strong></p>
<p>Mike proposes another idea &#8212; don&#8217;t use foreign keys!  Mike&#8217;s good about coming up with ideas no one else thinks of, but in this case, is this going too far? Can you justify the tradeoff of data integrity for avoiding deadlocks?   Personally, data integrity is more important.  Despite this, I want to argue Mike&#8217;s side a bit more, b/c well, there are never hard and fast rules in software, like &#8220;you must always use foreign keys&#8221;.</p>
<p>Foreign keys causes additional locks that you may not be aware of &#8212; beyond dictating the order you modify records.  Let&#8217;s say you have the following two tables: Player and Team.  There is a foreign key from the Player table to the Team table. The Team table has the following records:</p>
<table border="1">
<tr>
<th>TeamID</th>
<th>TeamName</th>
</tr>
<tr>
<td>1</td>
<td>Manchester United</td>
</tr>
<tr>
<td>2</td>
<td>Liverpool</td>
</tr>
</table>
<p>The Player table has the following record:</p>
<table border="1">
<tr>
<th>PlayerID</th>
<th>TeamID</th>
<th>PlayerName</th>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>Gerrard</td>
</tr>
</table>
<p>So Gerrard plays for Liverpool.  Two impossible things are about to happen: a) Manchester United is going to be relegated (so we need to delete the team), and Gerrard is going to play for Manchester United.</p>
<p>User A executes the following statement:</p>
<blockquote><p> BEGIN TRAN;</p>
<p>DELETE FROM Team WHERE TeamID = 1;</p></blockquote>
<p>Internally in SQL Server, the table looks like:</p>
<table border="1">
<tr>
<th>TeamID</th>
<th>TeamName</th>
<th></th>
</tr>
<tr>
<td>1</td>
<td>Manchester United</td>
<td>marked to be deleted and locked</td>
</tr>
<tr>
<td>2</td>
<td>Liverpool</td>
<td>&nbsp;</td>
</tr>
</table>
<p>When User B executes the following statement, it will block, b/c it is attempting to read Team 1 (Man U), but the record is locked and can&#8217;t be read.</p>
<blockquote><p>BEGIN TRAN;</p>
<p>UPDATE Player SET TeamID = 1 WHERE PlayerID = 1;</p></blockquote>
<p>The statement is blocked and waiting for the first user to commit the transaction.  Foreign keys cause additional locks to be made.  Not only that, but the locking goes from a child table to a parent table!  This is in the opposite order we modify the records which can lead to deadlocks! (Even though the example above includes a DELETE on the team table, an UPDATE would lock exactly the same way in case you are thinking about doing logical deletes).</p>
<p>Mike&#8217;s post talks about a potential new feature in SQL Server where constraints are checked when the transaction is committed, not when individual records are modified, but is it really the answer?  It will delay the foreign checking until the transaction is committed, but while it is checking the constraint, it will lock the records.  This causes the locking for the whole transaction to be in random order, which will cause deadlocks.</p>
<p><strong>SELECTs Lock Too! </strong></p>
<p>Another thing on deadlocks, SELECTs lock records too!  And therefore can deadlock.  With joins, it&#8217;s anyone&#8217;s guess the order in which it locks records (parents first, or children first).  As it turns out, most of the deadlocks I&#8217;ve seen have come from SELECT statements.  The best way to avoid SELECT statements that lock in SQL Server 2005 is to use <a href="http://msdn2.microsoft.com/en-us/library/tcbchxcb(vs.80).aspx">READ_COMMITTED_SNAPSHOT</a>. To enable it, run the following code:</p>
<p><code>ALTER DATABASE MyDatabase<br />
SET READ_COMMITTED_SNAPSHOT ON</code></p>
<p>It works very much like READ_COMMITTED, however without locking records.  The downside is that READ_COMMITTED_SNAPSHOT uses more I/O than READ_COMMITTED.</p>
<p><strong>Personal Preference </strong></p>
<p>To avoid deadlocks I have a bias towards the following approach.  After reading the above, you know there is no silver bullet, but this is a good balance of deadlock avoidance, data integrity, and ease of programming:</p>
<ul>
<li>Use foreign keys</li>
<li>Do logical deletes</li>
<li>INSERT, UPDATE and Logically delete tables in the same order</li>
<li>Use READ_COMMITTED_SNAPSHOT isolation level.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://clay.lenharts.net/blog/2007/11/17/are-foreign-keys-bad/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>
