<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Omar AL Zabir blog on ASP.NET Ajax and .NET 3.5 : sql server</title><link>http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx</link><description>Tags: sql server</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Optimize ASP.NET Membership Stored Procedures for greater speed and scalability</title><link>http://msmvps.com/blogs/omar/archive/2009/03/13/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx</link><pubDate>Fri, 13 Mar 2009 13:23:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1678004</guid><dc:creator>omar</dc:creator><slash:comments>8</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1678004</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/03/13/optimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx#comments</comments><description>&lt;p&gt;Last year at &lt;a href="http://www.pageflakes.com" title="Pageflakes - Web 2.0 AJAX portal" target="_blank"&gt;Pageflakes&lt;/a&gt;, when we were getting millions of hits per day, we were having query timeout due to lock timeout and Transaction Deadlock errors. These locks were produced from &lt;code&gt;aspnet_Users&lt;/code&gt; and &lt;code&gt;aspnet_Membership&lt;/code&gt; tables. Since both of these tables are very high read (almost every request causes a read on these tables) and high write (every anonymous visit creates a row on &lt;code&gt;aspnet_Users&lt;/code&gt;), there were just way too many locks created on these tables per second. SQL Counters showed thousands of locks per second being created. Moreover, we had queries that would select thousands of rows from these tables frequently and thus produced more locks for longer period, forcing other queries to timeout and thus throw errors on the website.&lt;/p&gt;
&lt;p&gt;If you have &lt;a href="http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx" title="Solve Transaction Deadlock and Lock Contention in Linq to Sql" target="_blank"&gt;read my last blog post&lt;/a&gt;, you know why such locks happen. Basically every table when it grows up to hold millions of records and becomes popular goes through this trouble. It&amp;rsquo;s just a part of scalability problem that is common to database. But we rarely take prevention about it in our early design.&lt;/p&gt;
&lt;p&gt;The solution is simple, you should either have &lt;code&gt;WITH (NOLOCK)&lt;/code&gt; or &lt;code&gt;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED&lt;/code&gt; before SELECT queries. Either of this will do. They tell SQL Server not to hold any lock on the table while it is reading the table. If some row is locked while the read is happening, it will just ignore that row. When you are reading a table thousand times per second, without these options, you are issuing lock on many places around the table thousand times per second. It not only makes read from table slower, but also so many lock prevents insert, update, delete from happening timely and thus queries timeout. If you have queries like &amp;ldquo;show the currently online users from last one hour based on &lt;code&gt;LastActivityDate&lt;/code&gt; field&amp;rdquo;, that is going to issue such a wide lock that even other harmless select queries will timeout. And did I tell you that there&amp;rsquo;s no index on &lt;code&gt;LastActivityDate&lt;/code&gt; on &lt;code&gt;aspnet_Users&lt;/code&gt; table?&lt;/p&gt;
&lt;p&gt;Now don&amp;rsquo;t blame yourself for not putting either of these options on your every stored proc and every dynamically generated SQL from the very first day. ASP.NET developers made the same mistake. You won&amp;rsquo;t see either of these used in any of the stored procs used by ASP.NET Membership. For example, the following stored proc gets called whenever you access &lt;code&gt;Profile&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ALTER PROCEDURE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[dbo]&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName             &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc       &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM &lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;      dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Applications &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;) = &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredApplicationName&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;&lt;br /&gt;    SELECT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM   &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AND &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredUserName &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;    SELECT TOP &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;1 &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyNames&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesString&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesBinary&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM         &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Profile&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@@ROWCOUNT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;0&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;        UPDATE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;=&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;br /&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;There are two SELECT operations that hold lock on two very high read tables &amp;ndash; &lt;code&gt;aspnet_Users&lt;/code&gt; and &lt;code&gt;aspnet_Profile&lt;/code&gt;. Moreover, there&amp;rsquo;s a nasty UPDATE statement. It tries to update the &lt;code&gt;LastActivityDate&lt;/code&gt; of a user whenever you access &lt;code&gt;Profile&lt;/code&gt; object for the first time within a http request. &lt;/p&gt;
&lt;p&gt;This stored proc alone is enough to bring your site down. It did to us because we are using &lt;code&gt;Profile&lt;/code&gt; Provider everywhere. This stored proc was called around 300 times/sec. We were having nightmarish slow performance on the website and many lock timeouts and transaction deadlocks. So, we added the transaction isolation level and we also modified the UPDATE statement to only perform an update when the &lt;code&gt;LastActivityDate&lt;/code&gt; is over an hour. So, this means, the same user&amp;rsquo;s &lt;code&gt;LastActivityDate&lt;/code&gt; won&amp;rsquo;t be updated if the user hits the site within the same hour.&lt;/p&gt;
&lt;p&gt;So, after the modifications, the stored proc looked like this:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ALTER PROCEDURE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[dbo]&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;[aspnet_Profile_GetProperties]&lt;br /&gt;    @ApplicationName      &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName             &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;nvarchar&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;256&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;),&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc       &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 1. Please no more locks during reads&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;--SELECT  @ApplicationId = NULL&lt;br /&gt;    --SELECT  @ApplicationId = ApplicationId FROM dbo.aspnet_Applications &lt;br /&gt;    WHERE LOWER(@ApplicationName) = LoweredApplicationName&lt;br /&gt;    --IF (@ApplicationId IS NULL)&lt;br /&gt;    --    RETURN&lt;br /&gt;    &lt;br /&gt;    -- 2. No more call to Application table. We have only one app dude!&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;udfGetAppId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;()&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;br /&gt;    DECLARE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;datetime&lt;br /&gt;    SELECT  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;NULL&lt;br /&gt;&lt;br /&gt;    SELECT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM   &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@ApplicationId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AND &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LoweredUserName &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;LOWER&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserName&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IS NULL&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURN&lt;br /&gt;    SELECT TOP &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;1 &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyNames&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesString&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;PropertyValuesBinary&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;FROM         &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Profile&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@@ROWCOUNT &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;0&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 3. Do not update the same user within an hour&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;IF DateDiff&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;n&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;) &amp;gt; &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#8acccf;"&gt;60&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;BEGIN&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#7f9f7f;"&gt;-- 4. Use ROWLOCK to lock only a row since we know this query&lt;br /&gt;            -- is highly selective&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;UPDATE &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;aspnet_Users &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WITH&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;ROWLOCK&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;SET    &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;LastActivityDate&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;=&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@CurrentTimeUtc&lt;br /&gt;            &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;WHERE  &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;UserId &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;@UserId&lt;br /&gt;        &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;br /&gt;    END&lt;br /&gt;END&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;The changes I made are numbered and commented. No need for further explanation. The only tricky thing here is, I have eliminate call to Application table just to get the ApplicationID from ApplicationName. Since there&amp;rsquo;s only one application in a database (ever heard of multiple applications storing their user separately on the same database and the same table?), we don&amp;rsquo;t need to look up the ApplicationID on every call to every Membership stored proc. We can just get the ID and hard code it in a function.&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;CREATE FUNCTION &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;dbo&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;udfGetAppId&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;()&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;RETURNS uniqueidentifier&lt;br /&gt;WITH EXECUTE AS &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dfdfbf;"&gt;CALLER&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;    RETURN CONVERT&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;uniqueidentifier&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#c89191;"&gt;&amp;#39;fd639154-299a-4a9d-b273-69dc28eb6388&amp;#39;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#eaeaac;"&gt;END&lt;/span&gt;&lt;span style="background:#3f3f3f none repeat scroll 0% 0%;-moz-background-clip:-moz-initial;-moz-background-origin:-moz-initial;-moz-background-inline-policy:-moz-initial;color:#dcdccc;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This UDF returns the &lt;code&gt;ApplicationID&lt;/code&gt; that I have hardcoded copying from the Application table. Thus it eliminates the need for quering on the Application table. &lt;/p&gt;
&lt;p&gt;Similarly you should do the changes in all other stored procedures that belong to Membership Provider. All the stroc procs are missing proper locking, issues aggressive lock during update and too frequent updates than practical need. Most of them also try to resolve ApplicationID from ApplicationName, which is unnecessary when you have only one web application per database. Make these changes and enjoy lock contention free super performance from Membership Provider!&lt;/p&gt;
&lt;div class="wlWriterHeaderFooter" style="margin:0px;padding:4px;text-align:left;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="http://widgets.dzone.com/widgets/zoneit.js" language="javascript"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f14%2foptimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f14%2foptimize-asp-net-membership-stored-procedures-for-greater-speed-and-scalability.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1678004" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads</title><link>http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx</link><pubDate>Sat, 07 Mar 2009 07:30:52 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1676241</guid><dc:creator>omar</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1676241</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx#comments</comments><description>&lt;p&gt;When your database tables start accumulating thousands of rows and many users start working on the same table concurrently, SELECT queries on the tables start producing lock contentions and transaction deadlocks. This is a common problem in any high volume website. As soon as you start getting several concurrent users hitting your website that results in SELECT queries on some large table like &lt;u&gt;aspnet_users&lt;/u&gt; table that are also being updated very frequently, you end up having one of these errors:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Transaction (Process ID ##) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Or,&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Timeout Expired. The Timeout Period Elapsed Prior To Completion Of The Operation Or The Server Is Not Responding. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The solution to these problems are – use proper index on the table and use transaction isolation level &lt;u&gt;Read Uncommitted&lt;/u&gt; or &lt;u&gt;WITH (NOLOCK)&lt;/u&gt; in your SELECT queries. So, if you had a query like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;SELECT * FORM aspnet_users &lt;br /&gt;&lt;span class="kwrd"&gt;where&lt;/span&gt; ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;You should end up having any of the above errors under high load. There are two ways to solve this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;SET TRANSACTION LEVEL READ UNCOMMITTED;
SELECT * FROM aspnet_Users &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Or use the WITH (NOLOCK):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;SELECT * FROM aspnet_Users WITH (NOLOCK) &lt;br /&gt;WHERE ApplicationID =’xxx’ AND LoweredUserName = &lt;span class="str"&gt;&amp;#39;someuser&amp;#39;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The reason for the errors are that since &lt;u&gt;aspnet_users&lt;/u&gt; is a high read and high write table, during read, the table is partially locked and during write, it is also locked. So, when the locks overlap on each other from several queries and especially when there’s a query that’s trying to read a large number of rows and thus locking large number of rows, some of the queries either timeout or produce deadlocks.&lt;/p&gt;

&lt;p&gt;Linq to Sql does not produce queries with the &lt;u&gt;WITH (NOLOCK)&lt;/u&gt; option nor does it use &lt;u&gt;READ UNCOMMITTED&lt;/u&gt;. So, if you are using Linq to SQL queries, you are going to end up with any of these problems on production pretty soon when your site becomes highly popular.&lt;/p&gt;

&lt;p&gt;For example, here’s a very simple query:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;using (&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;u&gt;DropthingsDataContext&lt;/u&gt; is a &lt;u&gt;DataContext&lt;/u&gt; built from &lt;a title="Dropthings - Open Source AJAX Portal" href="http://www.dropthings.com/" target="_blank"&gt;Dropthings&lt;/a&gt; database.&lt;/p&gt;

&lt;p&gt;When you attach SQL Profiler, you get this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_2B685BF8.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="174" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_7A197197.png" width="639" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You see none of the queries have READ UNCOMMITTED or WITH (NOLOCK). &lt;/p&gt;

&lt;p&gt;The fix is to do this:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;using (&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext2&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Open&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ExecuteCommand&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#c89191;"&gt;&amp;quot;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;&amp;quot;&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;);

    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This will result in the following profiler output&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_5DBC09AA.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="91" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_09202AA5.png" width="630" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you see, both queries execute within the same connection and the isolation level is set before the queries execute. So, both queries enjoy the isolation level.&lt;/p&gt;

&lt;p&gt;Now there’s a catch, the connection does not close. This seems to be a bug in the DataContext that when it is disposed, it does not dispose the connection it is holding onto. &lt;/p&gt;

&lt;p&gt;In order to solve this, I have made a child class of the &lt;u&gt;DropthingsDataContext&lt;/u&gt; named &lt;u&gt;DropthingsDataContext2&lt;/u&gt; which overrides the &lt;u&gt;Dispose&lt;/u&gt; method and closes the connection.&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;   &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;class &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext2 &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;: &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;, &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IDisposable
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;{
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;public new void &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
        {
            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;null&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
                &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;if &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;State &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;!= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;System&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Data&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;ConnectionState&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Closed&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
                {
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Close&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
                    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Connection&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
                }

            &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;base&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Dispose&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();            
        }
    }&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This solved the connection problem.&lt;/p&gt;

&lt;p&gt;There you have it, no more transaction deadlock or lock contention from Linq to SQL queries. But remember, this is only to eliminate such problems when your database already has the right indexes. If you do not have the proper index, then you will end up having lock contention and query timeouts anyway.&lt;/p&gt;

&lt;p&gt;There’s one more catch, READ UNCOMMITTED will return rows from transactions that have not completed yet. So, you might be reading rows from transactions that will rollback. Since that’s generally an exceptional scenario, you are more or less safe with uncommitted read, but not for financial applications where transaction rollback is a common scenario. In such case, go for committed read or repeatable read.&lt;/p&gt;

&lt;p&gt;There’s another way you can achieve the same, which seems to work, that is using .NET Transactions. Here’s the code snippet:&lt;/p&gt;

&lt;pre class="code" style="background:#3f3f3f;"&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;using &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;transaction &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;TransactionScope&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TransactionScopeOption&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;RequiresNew&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TransactionOptions&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;()
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;IsolationLevel &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;IsolationLevel&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ReadUncommitted&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;,
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Timeout &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#2b91af;"&gt;TimeSpan&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;FromSeconds&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#8acccf;"&gt;30&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;)
    }))
{
    &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;using &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;(&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;new &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#f0dfaf;"&gt;DropthingsDataContext&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;())
    {
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;db&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;aspnet_Users&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;First&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#eaeaac;"&gt;var &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;pages &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;= &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;user&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Pages&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;ToList&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();

        &lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;transaction&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;.&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dfdfbf;"&gt;Complete&lt;/span&gt;&lt;span style="background:#3f3f3f;color:#dcdccc;"&gt;();
    }
}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Profiler shows a transaction begins and ends:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_48683F55.png"&gt;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="273" alt="image" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/image_5F00_thumb_5F00_0F118CC6.png" width="499" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The downside is it wraps your calls in a transaction. So, you are unnecessarily creating transactions even for SELECT operations. When you do this hundred times per second on a web application, it’s a significant over head. &lt;/p&gt;

&lt;p&gt;Some really good examples of deadlocks are given in this article:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2" href="http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2"&gt;http://www.code-magazine.com/article.aspx?quickid=0309101&amp;amp;page=2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I highly recommend it.&lt;/p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f07%2flinq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2009%2f03%2f07%2flinq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx" border="0" /&gt;&lt;/a&gt;&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;&lt;script type="text/javascript"&gt;var dzone_url = &amp;#39;http://msmvps.com/blogs/omar/archive/2009/03/07/linq-to-sql-solve-transaction-deadlock-and-query-timeout-problem-using-uncommitted-reads.aspx&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_title = &amp;#39;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_blurb = &amp;#39;Linq to SQL solve Transaction deadlock and Query timeout problem using uncommitted reads&amp;#39;;&lt;/script&gt;&lt;script type="text/javascript"&gt;var dzone_style = &amp;#39;2&amp;#39;;&lt;/script&gt;&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt; &lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1676241" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category></item><item><title>99.99% available ASP.NET and SQL Server SaaS Production Architecture</title><link>http://msmvps.com/blogs/omar/archive/2008/12/10/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx</link><pubDate>Wed, 10 Dec 2008 08:39:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1656383</guid><dc:creator>omar</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1656383</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/12/10/99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx#comments</comments><description>&lt;p&gt;You have a hot ASP.NET+SQL Server product, growing at thousand users per day and you have hit the limit of your own garage hosting capability. Now that you have enough VC money in your pocket, you are planning to go out and host on some real hosting facility, maybe a colocation or managed hosting. So, you are thinking, how to design a physical architecture that will ensure performance, scalability, security and availability of your product? How can you achieve four-nine (99.99%) availability? How do you securely let your development team connect to production servers? How do you choose the right hardware for web and database server? Should you use Storage Area Network (SAN) or just local disks on RAID? How do you securely connect your office computers to production environment?&lt;/p&gt;
&lt;p&gt;Here I will answer all these queries. Let me first show you a diagram that I made for &lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt; where we ensured we get four-nine availability. Since Pageflakes is a &lt;a href="http://en.wikipedia.org/wiki/Software_as_a_service"&gt;Level 3 SaaS&lt;/a&gt;, it&amp;rsquo;s absolutely important that we build a high performance, highly available product that can be used from anywhere in the world 24/7 and end-user gets quick access to their content with complete personalization and customization of content and can share it with others and to the world. So, you can take this production architecture as a very good candidate for Level 3 SaaS: &lt;/p&gt;
&lt;p&gt;&lt;a href="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/Hosting_5F00_environment_5F00_7C36AD9E.png"&gt;&lt;img title="Hosting_environment" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" alt="Hosting_environment" src="http://msmvps.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/omar/Hosting_5F00_environment_5F00_thumb_5F00_45D55FC2.png" border="0" height="832" width="600" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a CodeProject article that explains all the ideas:&lt;/p&gt;
&lt;p&gt;&lt;a title="99.99% available ASP.NET and SQL Server SaaS Production Architecture" href="http://www.codeproject.com/KB/aspnet/ProdArch.aspx" target="_blank"&gt;99.99% available ASP.NET and SQL Server SaaS Production Architecture&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope you like it. Appreciate your vote.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:B3E14793-948F-49af-A347-D19C374A7C4F:25404c3d-2014-4892-a108-bf1cfc5d1ff8" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;div class="wlWriterHeaderFooter" style="text-align:left;margin:0px;padding:4px 4px 4px 4px;"&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;&lt;/script&gt;
&lt;script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;
&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f12%2f10%2f99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fmsmvps.com%2fblogs%2fomar%2farchive%2f2008%2f12%2f10%2f99-99-available-asp-net-and-sql-server-saas-production-architecture.aspx" alt="kick it on DotNetKicks.com" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1656383" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/pageflakes/default.aspx">pageflakes</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/architecture/default.aspx">architecture</category></item><item><title>My first book - Building a Web 2.0 Portal with ASP.NET 3.5</title><link>http://msmvps.com/blogs/omar/archive/2008/01/13/my-first-book-building-a-web-2-0-portal-with-asp-net-3-5.aspx</link><pubDate>Sun, 13 Jan 2008 20:23:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1461326</guid><dc:creator>omar</dc:creator><slash:comments>44</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1461326</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2008/01/13/my-first-book-building-a-web-2-0-portal-with-asp-net-3-5.aspx#comments</comments><description>&lt;p&gt;My first book &amp;quot;&lt;a href="http://www.oreilly.com/catalog/9780596510503/" target="_blank"&gt;Building a Web 2.0 Portal with ASP.NET 3.5&lt;/a&gt;&amp;quot; from O&amp;#39;Reilly is published and available in the stores. This book explains in detail the architecture design, development, test, deployment, performance and scalability challenges of my open source web portal &lt;a href="http://www.dropthings.com" target="_blank"&gt;Dropthings.com&lt;/a&gt;. Dropthings is a prototype of a web portal similar to &lt;a href="http://www.google.com/ig" target="_blank"&gt;iGoogle&lt;/a&gt; or &lt;a href="http://www.pageflakes.com" target="_blank"&gt;Pageflakes&lt;/a&gt;. But this portal is developed using recently released brand new technologies like ASP.NET 3.5, C# 3.0, Linq to Sql, Linq to XML, and Windows Workflow foundation. It makes heavy use of ASP.NET AJAX 1.0. Throughout my career I have built several state-of-the-art &lt;a href="http://omar.mvps.org" target="_blank"&gt;personal&lt;/a&gt;, educational, enterprise and &lt;a href="http://www.pageflakes.com" target="_blank"&gt;mass consumer web portals&lt;/a&gt;. This book collects my experience in building all of those portals.&lt;/p&gt;&lt;p&gt;O&amp;#39;Reilly Website:&lt;br /&gt;&lt;a href="http://www.oreilly.com/catalog/9780596510503/"&gt;http://www.oreilly.com/catalog/9780596510503/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Amazon:&lt;br /&gt;&lt;a href="http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500"&gt;http://www.amazon.com/Building-Web-2-0-Portal-ASP-NET/dp/0596510500&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Disclaimer: This book does not show you how to build Pageflakes. Dropthings is entirely different in terms of architecture, implementation and the technologies involved.&lt;/p&gt; &lt;p&gt;You learn how to: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Implement a highly decoupled architecture following the popular n-tier, widget-based application model  &lt;/li&gt;&lt;li&gt;Provide drag-and-drop functionality, and use ASP.NET 3.5 to build the server-side part of the web layer  &lt;/li&gt;&lt;li&gt;Use LINQ to build the data access layer, and Windows Workflow Foundation to build the business layer as a collection of workflows  &lt;/li&gt;&lt;li&gt;Build client-side widgets using JavaScript for faster performance and better caching  &lt;/li&gt;&lt;li&gt;Get maximum performance out of the ASP.NET AJAX Framework for faster, more dynamic, and scalable sites  &lt;/li&gt;&lt;li&gt;Build a custom web service call handler to overcome shortcomings in ASP.NET AJAX 1.0 for asynchronous, transactional, cache-friendly web services  &lt;/li&gt;&lt;li&gt;Overcome JavaScript performance problems, and help the user interface load faster and be more responsive  &lt;/li&gt;&lt;li&gt;Solve various scalability and security problems as your site grows from hundreds to millions of users  &lt;/li&gt;&lt;li&gt;Deploy and run a high-volume production site while solving software, hardware, hosting, and Internet infrastructure problems &lt;/li&gt;&lt;/ul&gt;If you&amp;#39;re ready to build state-of-the art, high-volume web applications that can withstand millions of hits per day, this book has exactly what you need.&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1461326" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/asp.net/default.aspx">asp.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/pageflakes/default.aspx">pageflakes</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/linq/default.aspx">linq</category><category domain="http://msmvps.com/blogs/omar/archive/tags/workflow/default.aspx">workflow</category><category domain="http://msmvps.com/blogs/omar/archive/tags/ajax/default.aspx">ajax</category><category domain="http://msmvps.com/blogs/omar/archive/tags/.net/default.aspx">.net</category><category domain="http://msmvps.com/blogs/omar/archive/tags/IIS/default.aspx">IIS</category></item><item><title>A significant part of sql server process memory has been paged out. This may result in performance degradation</title><link>http://msmvps.com/blogs/omar/archive/2007/09/19/a-significant-part-of-sql-server-process-memory-has-been-paged-out-this-may-result-in-performance-degradation.aspx</link><pubDate>Wed, 19 Sep 2007 07:46:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1205524</guid><dc:creator>omar</dc:creator><slash:comments>31</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=1205524</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/09/19/a-significant-part-of-sql-server-process-memory-has-been-paged-out-this-may-result-in-performance-degradation.aspx#comments</comments><description>&lt;p&gt;If you are using SQL Sever Server standard edition 64 bit on a Windows 2003 64bit, you will frequently encounter this problem where SQL Server says:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;A significant part of sql server process memory has been paged out. This may result in performance degradation. Duration 0 seconds. Working set (KB) 25432, committed (KB) 11296912, memory utilization 0%&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The number in working set and duration will vary. What happens here is SQL Server is forced to release memory to operating system because some other application or OS itself needs to allocate RAM.&lt;/p&gt; &lt;p&gt;We went through many support articles like:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://support.microsoft.com/kb/918483"&gt;918483&lt;/a&gt;: How to reduce paging of buffer pool memory in the 64-bit version of SQL Server 2005  &lt;li&gt;&lt;a href="http://support.microsoft.com/kb/905865/"&gt;905865&lt;/a&gt;: The sizes of the working sets of all the processes in a console session may be trimmed when you use Terminal Services to log on to or log off from a computer that is running Windows Server 2003  &lt;li&gt;&lt;a href="http://support.microsoft.com/kb/920739/"&gt;920739&lt;/a&gt;: You may experience a decrease in overall system performance when you are copying files that are larger than approximately 500 MB in Windows Server 2003 Service Pack 1 &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;But nothing solved the problem. We still have the page out problem happening every day.&lt;/p&gt; &lt;p&gt;The server has 16 GB RAM where 12 GB is maximum limit allocated to SQL Server. 4 GB is left to OS and and other application. We have also turned off antivirus and any large backup job. 12 GB RAM should be plenty because there&amp;#39;s no other app running on the dedicated SQL Server box. But the page out still happens. When this happens, SQL Server becomes very slow. Queries timeout, website throws error, transactions abort. Sometimes this problems goes on for 30 to 40 minutes and website becomes slow/unresponsive during that time.&lt;/p&gt; &lt;p&gt;I have found what causes SQL Server to page out. File System cache somehow gets really high and forces SQL Server to trim down.&lt;/p&gt; &lt;p&gt;&lt;img height="663" alt="clip_image002" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image002.jpg" width="557" /&gt; &lt;/p&gt; &lt;p&gt;You see the System cache resident bytes are very high. During this time SQL Server gets much less RAM than it needs. Queries timeout at very high rate like 15 per sec. Moreover, there&amp;#39;s high SQL Lock Timeout/sec (around 15/sec not captured in screen shot).&lt;/p&gt; &lt;p&gt;&lt;img height="191" alt="clip_image004" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image004.jpg" width="549" /&gt; &lt;/p&gt; &lt;p&gt;SQL Server max memory is configured 12 GB. But here it shows it’s getting less than 8 GB.&lt;/p&gt; &lt;p&gt;While the file system cache is really high, there’s no process that’s taking significant RAM.&lt;/p&gt; &lt;p&gt;&lt;img height="648" alt="clip_image006" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image006.jpg" width="340" /&gt; &lt;/p&gt; &lt;p&gt;After I used SysInternal’s &lt;a href="http://www.microsoft.com/technet/sysinternals/FileAndDisk/CacheSet.mspx"&gt;CacheSet&lt;/a&gt; to reset file system cache and set around 500 MB as max limit, memory started to free up.&lt;/p&gt; &lt;p&gt;&lt;img height="285" alt="clip_image008" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image008.jpg" width="557" /&gt; &lt;/p&gt; &lt;p&gt;SQL Server started to see more RAM free:&lt;/p&gt; &lt;p&gt;&lt;img height="92" alt="clip_image010" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image010.jpg" width="564" /&gt; &lt;/p&gt; &lt;p&gt;Then I hit the “Clear” button to clear file system cache and it came down dramatically.&lt;/p&gt; &lt;p&gt;&lt;img height="668" alt="clip_image012" src="http://omar.mvps.org/images/SQLServerhaspagedoutsignificant_10B/clip_image012.jpg" width="553" /&gt; &lt;/p&gt; &lt;p&gt;Paging stopped. System cache was around 175 MB only. SQL Server lock timeout came back to zero. Everything went back to normal.&lt;/p&gt; &lt;p&gt;So, I believe there&amp;#39;s either some faulty driver or the OS itself is leaking file system cache in 64bit environment.&lt;/p&gt; &lt;p&gt;What we have done is, we have a dedicated person who goes to production database servers every hour, runs the CacheSet program and clicks &amp;quot;Clear&amp;quot; button. This clears the file system cache and prevents it from growing too high.&lt;/p&gt; &lt;p&gt;There are lots of articles written about this problem. However, the most informative one I have found is from the SQL Server PSS team:&lt;/p&gt; &lt;p&gt;&lt;a title="http://blogs.msdn.com/psssql/archive/2007/05/31/the-sql-server-working-set-message.aspx" href="http://blogs.msdn.com/psssql/archive/2007/05/31/the-sql-server-working-set-message.aspx"&gt;http://blogs.msdn.com/psssql/archive/2007/05/31/the-sql-server-working-set-message.aspx&lt;/a&gt; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;UPDATE - THE FINAL SOLUTION!&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The final solution is to run this program on Windows Startup:&lt;/p&gt; &lt;p&gt;SetSystemFileCacheSize 128 256&lt;/p&gt; &lt;p&gt;This sets the lower and higher limit for the System Cache. You need to run this on every windows startup because a restart will undo the cache setting to unlimited.&lt;/p&gt; &lt;p&gt;You can run the program without any parameter to see what is the current setting.&lt;/p&gt; &lt;p&gt;Download the program from this page:&lt;/p&gt; &lt;p&gt;&lt;a title="http://www.uwe-sieber.de/ntcacheset_e.html" href="http://www.uwe-sieber.de/ntcacheset_e.html"&gt;http://www.uwe-sieber.de/ntcacheset_e.html&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Go to the end and you will get the link to the SetSystemFileCacheSize.zip&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1205524" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category><category domain="http://msmvps.com/blogs/omar/archive/tags/performance/default.aspx">performance</category><category domain="http://msmvps.com/blogs/omar/archive/tags/pageflakes/default.aspx">pageflakes</category><category domain="http://msmvps.com/blogs/omar/archive/tags/production/default.aspx">production</category><category domain="http://msmvps.com/blogs/omar/archive/tags/optimize/default.aspx">optimize</category></item><item><title>Think you know how to write UPDATE statement? Think again.</title><link>http://msmvps.com/blogs/omar/archive/2007/01/20/think-you-know-how-to-write-update-statement-think-again.aspx</link><pubDate>Sat, 20 Jan 2007 17:47:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:507158</guid><dc:creator>omar</dc:creator><slash:comments>26</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=507158</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2007/01/20/think-you-know-how-to-write-update-statement-think-again.aspx#comments</comments><description>&lt;p&gt;When I was a kid, my mom used to read me UPDATE queries every
night before I went to sleep. I heared many stories about updating
objects to database where most of them were the same old:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a99eb7d5-63bb-4f1c-aef5-e41e2e59d741" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;UPDATE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;Table&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;SET&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Field1&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Value1, Field2&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Value2, . . .&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;WHERE&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;PRIMARYKEY&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;TheKey&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So, I grew up with the same ideas on how to update objects in
tables as other kids do. All the UPDATE queries involved taking all
the fields and the update stored procedures used to have all the
properties of the objects. If you are using some Code Generators
(e.g. Code Smith) and generating data access layer codes and stored
procedures for objects, you will see almost all the code generators
and ORM tools generate UPDATE statments with all the fields in the
SET block. Let me show you with an example how evil this idea
is.&lt;/p&gt;
&lt;p&gt;Imagine a table like this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:a2c89743-a049-4619-9332-8eba9cef4921" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;CREATE&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;TABLE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;dbo&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelSubscribedByUser&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;int&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#FF00FF;"&gt;IDENTITY&lt;/span&gt;
&lt;span style="color:#000000;"&gt;(&lt;/span&gt;
&lt;span style="color:#800000;font-weight:bold;"&gt;1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt;
&lt;span style="color:#800000;font-weight:bold;"&gt;1&lt;/span&gt;
&lt;span style="color:#000000;"&gt;)&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;NOT&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;NULL&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;UserId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;int&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;NOT&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;NULL&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;int&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;NOT&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;NULL&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;image&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;NOT&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;NULL&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;CONSTRAINT&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;PK_ChannelSubscribedByUser&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;PRIMARY&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;KEY&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;CLUSTERED&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;(&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;UserId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;ASC&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;ASC&lt;/span&gt;
&lt;span style="color:#000000;"&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is a table from 
&lt;a href="http://www.pageflakes.com"&gt;Pageflakes&lt;/a&gt; database. In
this table, we store all the RSS feeds user has read from a
particular RSS channel. UserId is a foreign key to User table and
ChannelID is a foreign key to Channel table. Pretty straight
forward. We had a harmless update stored procedure generated using
Code Smith using the famous .NET Tiers template.&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:27bf71fe-2772-4e33-94f5-972f03d1e8ca" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;ALTER&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;PROCEDURE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;dbo&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;.&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;prcChannelSubscribedByUserUpdate&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ID&lt;/span&gt; 
&lt;span style="color:#000000;font-weight:bold;"&gt;int&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ChannelId&lt;/span&gt; 
&lt;span style="color:#000000;font-weight:bold;"&gt;int&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ReadRSSItemIDs&lt;/span&gt; 
&lt;span style="color:#000000;font-weight:bold;"&gt;image&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@UserId&lt;/span&gt; 
&lt;span style="color:#000000;font-weight:bold;"&gt;int&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;AS&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;UPDATE&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;dbo.&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelSubscribedByUser&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;SET&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ChannelId&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;UserId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@UserId&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;WHERE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ID&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;SELECT&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;UserId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelId&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;FROM&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;dbo.&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelSubscribedByUser&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;WHERE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ID&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Look at the query plan and see how horrible it really is:&lt;/p&gt;
&lt;p&gt;
&lt;img height="179" src="http://omar.mvps.org/images/ThinkyouknowhowtowriteUPDATEstatementTh_144B6/image09.png" width="800" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;There are 2 Clustered Index Seeks, one Table Spool (very
expensive), 2 Nested Loops, 1 Assert, 1 Clustered Index Seek. If
you look at the IO Statistics, you can see how truly evil this
query is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Table &amp;#39;RSSChannel&amp;#39;. Scan count 0, logical reads 3, physical
reads 0, read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
&lt;br /&gt;Table &amp;#39;PageFlakesUser&amp;#39;. Scan count 0, logical reads 3,
physical reads 0, read-ahead reads 0, lob logical reads 0, lob
physical reads 0, lob read-ahead reads 0.
&lt;br /&gt;Table &amp;#39;ChannelSubscribedByUser&amp;#39;. Scan count 1, logical reads
15, physical reads 0, read-ahead reads 0, lob logical reads 3, lob
physical reads 0, lob read-ahead reads 0.
&lt;br /&gt;Table &amp;#39;Worktable&amp;#39;. Scan count 1, logical reads 5, physical
reads 0, read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is making SQL Server go to the tables which are refered as
foreign key during a single row update!&lt;/p&gt;
&lt;p&gt;Generally when we update a row in a table which represents an
object, we rarely change the value of the fields which are foreign
keys to other tables and has index on them. Most of the time, the
updates are on the fields which contain properties, not relations.
For example, 99% of the cases, you will update properties of an 
&lt;u&gt;Employee&lt;/u&gt; object like 
&lt;u&gt;FirstName&lt;/u&gt;, 
&lt;u&gt;LastName&lt;/u&gt;, 
&lt;u&gt;Age&lt;/u&gt; etc. 1% case you will modify the 
&lt;u&gt;CompanyID&lt;/u&gt; (because s/he was fired)&amp;nbsp;which is a foreign
key to Company Table. But if you go to your database and see the
stored procedure which updates the 
&lt;u&gt;Employee&lt;/u&gt; object, you will see this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:4ff7e700-749e-4b64-952d-709f8a1950ca" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;UPDATE&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;Employee&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;SET&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;FirstName&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@FirstName&lt;/span&gt;
&lt;span style="color:#000000;"&gt;, LastName&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@LastName&lt;/span&gt;
&lt;span style="color:#000000;"&gt;, CompanyID&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@CompanyID&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;WHERE&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;EmployeeID&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@EmployeeID&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Don&amp;#39;t be ashamed. I know we all have queries like this every
where.&lt;/p&gt;
&lt;p&gt;If you remove those unwanted fields which generally have Foreign
Key and Index on them, you can gain significant performance
improvement. When I just change the UPDATE statement to this:&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:36f12e68-81c7-4887-a45b-cddcc3c08667" style="padding-right:0px;display:inline;padding-left:0px;float:none;padding-bottom:0px;margin:0px;padding-top:0px;"&gt;

&lt;pre style="background-color:White;"&gt;&lt;/pre&gt;
&lt;div&gt;

&lt;span style="color:#0000FF;"&gt;UPDATE&lt;/span&gt; 
&lt;span style="color:#000000;"&gt;dbo.&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ChannelSubscribedByUser&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt;
&lt;span style="color:#0000FF;"&gt;SET&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ReadRSSItemIDs&lt;/span&gt;
&lt;span style="color:#000000;"&gt;,&lt;/span&gt; 
&lt;span style="color:#0000FF;"&gt;WHERE&lt;/span&gt; 
&lt;span style="color:#FF0000;"&gt;[&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;ID&lt;/span&gt;
&lt;span style="color:#FF0000;"&gt;]&lt;/span&gt; 
&lt;span style="color:#808080;"&gt;=&lt;/span&gt; 
&lt;span style="color:#008000;"&gt;@ID&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;See the query plan:&lt;/p&gt;
&lt;p&gt;
&lt;img height="141" src="http://omar.mvps.org/images/ThinkyouknowhowtowriteUPDATEstatementTh_144B6/image011.png" width="700" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;There&amp;#39;s just one Clustered Index Update. No Table Spool, no
Clustered Index seeks, no nested loops, no asserts. The IO
statistics shows how significant the improvement really is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Table &amp;#39;ChannelSubscribedByUser&amp;#39;. Scan count 1, logical reads 6,
physical reads 0, read-ahead reads 0, lob logical reads 3, lob
physical reads 0, lob read-ahead reads 0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&amp;#39;s just one update and nothing else. Also the number of
Logical Reads is 6 compared to 15.&lt;/p&gt;
&lt;p&gt;So, you thought you knew how to write UPDATE statements? Think
again.&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=507158" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category></item><item><title>Large log file can bring SQL Server down when transaction log shipping runs</title><link>http://msmvps.com/blogs/omar/archive/2006/09/17/Large-log-file-can-bring-SQL-Server-down-when-transaction-log-shipping-runs.aspx</link><pubDate>Sun, 17 Sep 2006 06:04:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:130305</guid><dc:creator>omar</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=130305</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/17/Large-log-file-can-bring-SQL-Server-down-when-transaction-log-shipping-runs.aspx#comments</comments><description>&lt;p&gt;We were having very poor performance when we turned on transaction log shipping on our SQL Server. We are using SQL Server 2005. The transaction log file was around 30 GB because the database was in Full Recovery mode. The server became very slow, every 15 mins when we were doing the log shipping, it used to become very slow and sometimes nonresponsive. The event log was getting full of SqlTimeout exceptions generated by the web site. The web site started to show asp.net error page very frequently. We could not use SQL Server Management Studio to login to SQL Server so that we could do something about it.  &lt;p&gt;Here&amp;#39;s how the connection time was reported from an external monitoring site:  &lt;p&gt;&lt;img height="400" src="http://omar.mvps.org/images/LargelogfilecanbringSQLServerdownwhentra_A993/clip_image0011.png" width="600" alt="" /&gt;  &lt;p&gt;The peaks are 30 seconds which mean they timed out.  &lt;p&gt;So, here&amp;#39;s what we did:  &lt;ol&gt; &lt;li&gt;Turned off Log shipping  &lt;li&gt;Restarted SQL Server.  &lt;li&gt;Switched Database to Simple recovery model. Shrunk the log file. This made the log file come down to couple of megabytes.  &lt;li&gt;Ran for some days. All looked ok.  &lt;li&gt;Then switched DB to Full Recovery model and configured log shipping again.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;So far running fine. But we go down for an hour every Saturday when we run INDEX DEFRAG on the indexes. The log ships show around 5 or 6 log backups which are each 1 or 2 GB in size when the index defrag happens.&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=130305" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category></item><item><title>How to setup SQL Server 2005 Transaction Log Ship on large database that really works</title><link>http://msmvps.com/blogs/omar/archive/2006/09/15/How-to-setup-SQL-Server-2005-Transaction-Log-Ship-on-large-database-that-really-works.aspx</link><pubDate>Fri, 15 Sep 2006 10:01:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:128439</guid><dc:creator>omar</dc:creator><slash:comments>38</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/omar/rsscomments.aspx?PostID=128439</wfw:commentRss><comments>http://msmvps.com/blogs/omar/archive/2006/09/15/How-to-setup-SQL-Server-2005-Transaction-Log-Ship-on-large-database-that-really-works.aspx#comments</comments><description>&lt;p&gt;I tried a lot of combinations in my life in order to find out an
effective method for implementing Transaction Log Shipping between
servers which are in a workgroup, not under domain. I realized the
things you learn from article and books are for small and medium
sized databases. When you database become 10 GB or bigger, thing&amp;#39;s
become a lot harder than it looks. Additionally many things changed
in SQL Server 2005. So, it&amp;#39;s even more difficult to configure log
shipping properly nowadays.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the steps that I finally found that works. Let&amp;#39;s assume
there are 2 servers with SQL Server 2005. Make sure both servers
have latest SP. There&amp;#39;s Service Pack 1 released already.&lt;/p&gt;
&lt;p&gt;1. Create a new user Account named &amp;quot;SyncAccount&amp;quot; on both
computers. Use the exact same user name and password.&lt;/p&gt;
&lt;p&gt;2. Make sure File Sharing is enabled on the local area
connection between the server. Also enable file sharing in
Firewall.&lt;/p&gt;
&lt;p&gt;3. Make sure the local network connection is not regular LAN. It
must be a gigabit card with near zero data corruption. Both cable
and switch needs to be perfect. If possible, connect both servers
using Fibre optic cable directly on the NIC in order to avoid a
separate Switch.&lt;/p&gt;
&lt;p&gt;4. Now create a folder named &amp;quot;TranLogs&amp;quot; on both servers. Let&amp;#39;s
assume the folder is on E:\Tranlogs.&lt;/p&gt;
&lt;p&gt;5. On Primary Database server, share the folder &amp;quot;Tranlogs&amp;quot; and
allow SyncAccount &amp;quot;Full Access&amp;quot; to it. Then allow SyncAccount
FullAccess on TranLogs folder. So you are setting the same
permission from both &amp;quot;Sharing&amp;quot; tab and from &amp;quot;Security&amp;quot; tab.&lt;/p&gt;
&lt;p&gt;6. On Secondary database server, allow SyncAccount &amp;quot;Full Access&amp;quot;
right on TranLogs folder. No need to share it.&lt;/p&gt;
&lt;p&gt;7. Test whether SyncAccount can really connect between the
servers. On Secondary Server, go to Command Prompt and do this:&lt;/p&gt;
&lt;p&gt;8. 
&lt;img height="283" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0018.png" width="580" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;9. Now you have a command prompt which is running with
SyncAccount privilege. Let&amp;#39;s confirm the account can read and write
on &amp;quot;TranLog&amp;quot; shares on both servers.&lt;/p&gt;
&lt;p&gt;10. 
&lt;img height="113" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0026.png" width="580" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;11. This is exactly what SQL Agent will be doing during log
ship. It will copy log files from primary server&amp;#39;s network share to
it&amp;#39;s own log file folder. So, the SyncAccount needs to be able to
both read files from primary server&amp;#39;s network share and write onto
its own tranlogs folder. The above test verifies the result.&lt;/p&gt;
&lt;p&gt;12. This is something new in SQL Server 2005: Add SyncAccount in
SQLServer Agent group &amp;quot;SqlServer2005SqlAgentUser$....&amp;quot;. You will
find this Windows User Group after installing SQL Server 2005.&lt;/p&gt;
&lt;p&gt;13. Now go to Control Panel-&amp;gt;Administrative
Tools-&amp;gt;Services and find the SQL Server Agent service. Go to its
properties and set SyncAccount as the account on the Logon tab.
Restart the service. Do this on both servers.&lt;/p&gt;
&lt;p&gt;14. 
&lt;img height="384" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0046.jpg" width="336" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;15. I use sa account to configure the log shipping. So, do this
on both servers:&lt;/p&gt;
&lt;p&gt;a. Enable &amp;quot;sa&amp;quot; account. By default, sa is disabled in SQL Server
2005.&lt;/p&gt;
&lt;p&gt;b. On &amp;quot;sa&amp;quot; account turn off Password Expiration Policy. This
prevents sa password from expiring automatically.&lt;/p&gt;
&lt;p&gt;16. On Secondary server, you need to allow remote connections.
By default, SQL Server 2005 disables TCP/IP connection. As a
result, you cannot login to the server from another server. Launch
the Surface Area Configuration tool from Start-&amp;gt;Programs-&amp;gt;MS
SQL Server 2005 and go to &amp;quot;Remote Connection&amp;quot; section. Choose the
3rd option which allows both TCP/IP based remote connection and
local named pipe based connections.&lt;/p&gt;
&lt;p&gt;17. On Secondary Server firewall, open port 1433 so that primary
server can connect to it.&lt;/p&gt;
&lt;p&gt;18. Restart SQL Server. Yes, you need to restart SQL Server.&lt;/p&gt;
&lt;p&gt;18. On Primary server, go to Database properties-&amp;gt;Options and
set Recovery Model to &amp;quot;Full&amp;quot;. If it was already set to full before,
it will be wise to first set it to Simple, then shrink the
transaction log file and then make it &amp;quot;Full&amp;quot; again. This will
truncate the transaction log file for sure.&lt;/p&gt;
&lt;p&gt;
&lt;img height="384" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0056.png" width="428" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;19. Now take a Full Backup of the database. During backup, make
sure you put the backup file on a physically separate hard drive
than the drive where MDF is located. Remember, not different
logical drives, different physical drives. So, you should have at
least 2 hard drives on the server. During backup, SQL Server reads
from MDF and writes on the backup file. So, if both MDF and the
backup is done on the same hard drive, it&amp;#39;s going to take more than
double the time to backup the database. 
&lt;b&gt;It will also keep the Disk fully occupied and server will become
very slow.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0066.png" width="433" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;20. After backup done, RAR the database. This ensures when you
copy the database to the other server there&amp;#39;s no data corruption
while the file was being transferred. If you fail to unRAR the file
on the secondary server, you get assurance that there&amp;#39;s some
problem on the network and you must replace network infrastructure.
The RAR also should be done on a separate hard drive than the one
where the RAR is located. Same reason, read is on one drive and
write is on another drive. Better if you can directly RAR to the
destination server using network share. It has two benefits:&lt;/p&gt;
&lt;p&gt;a. Your server&amp;#39;s IO is saved. There&amp;#39;s no write, only read.&lt;/p&gt;
&lt;p&gt;b. Both RAR and network copy is done in one step.&lt;/p&gt;
&lt;p&gt;21. 
&lt;img height="266" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0076.png" width="283" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;22. By the time you are done with the backup, RAR, copy over
network, restore on the other server, the Transaction Log file
(LDF) on the primary database server might become very big. For us,
it becomes around 2 to 3 GB. So, we have to manually take a
transaction log backup and ship to the secondary server before we
configure Transaction Log Shipping.&lt;/p&gt;
&lt;p&gt;23. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0086.png" width="432" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;24. When you are done with copying the transaction log backup to
the second server, first restore the Full Backup on the secondary
server:&lt;/p&gt;
&lt;p&gt;25. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0096.png" width="432" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;26. But before restoring, go to Options tab and choose RESTORE
WITH STANDBY:&lt;/p&gt;
&lt;p&gt;27. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0106.png" width="433" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;28. When the full backup is restored, restore the transaction
log backup.&lt;/p&gt;
&lt;p&gt;
&lt;img height="393" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0126.jpg" width="436" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;29. 
&lt;b&gt;REMEMBER: go to options tab and set the Recovery State to
&amp;quot;RESTORE WITH STANDBY&amp;quot; before you hit the OK button.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;30. This generally takes a long time. Too long in fact. Every
time I do the manual full backup, rar, copy, unrar, restore, the
Transaction Log (LDF) file becomes 2 to 3 GB. As a result, it takes
a long time to do a transaction log backup, copy and restore and it
takes more than an hour to restore it. So, within this time, the
log file on the primary server again becomes large. As a result,
when log shipping starts, the first log ship is huge. So, you need
to plan this carefully and do it only when you have least amount of
traffic.&lt;/p&gt;
&lt;p&gt;31. I usually have to do this manual Transaction Log backup
twice. First one is around 3 GB. Second one is around 500 MB.&lt;/p&gt;
&lt;p&gt;32. Now you have a database on the secondary server ready to be
configured for Log shipping.&lt;/p&gt;
&lt;p&gt;33. Go to Primary Server, select the Database, right click
&amp;quot;Tasks&amp;quot; -&amp;gt; &amp;quot;Shrik&amp;quot;. Shrink the Log File.&lt;/p&gt;
&lt;p&gt;34. Go to Primary server, bring on Database options, go to
Transaction Log option and enable log shipping.&lt;/p&gt;
&lt;p&gt;35. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0136.png" width="432" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;36. Now configure the backup settings line this:&lt;/p&gt;
&lt;p&gt;37. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0146.png" width="416" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;38. Remember, the first path is the network path that we tested
from command prompt on the secondary server. The second path is the
local hard drive folder on the primary server which is shared and
accessible from the network path.&lt;/p&gt;
&lt;p&gt;39. Add a secondary server. This is the server where you have
restored the database backup&lt;/p&gt;
&lt;p&gt;40. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0156.png" width="433" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;41. Choose &amp;quot;No, the secondary database is initialized&amp;quot; because
we have already restored the database.&lt;/p&gt;
&lt;p&gt;42. Go to second tab &amp;quot;Copy Files&amp;quot; and enter the path on the
secondary server where log files will be copied to. Note: The
secondary server will fetch the log files from the primary server
network share to it&amp;#39;s local folder. So, the path you specify is on
the secondary server. Do not get confused from the picture below
that&amp;#39;s it&amp;#39;s the same path as primary server. I just have same
folder configuration on all servers. It can be D:\tranlogs if you
have the tranlogs folder on D: drive on secondary server.&lt;/p&gt;
&lt;p&gt;43. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0166.png" width="434" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;44. On third tab, &amp;quot;Restore Transaction Log&amp;quot; configure it as
following:&lt;/p&gt;
&lt;p&gt;45. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0176.png" width="433" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;46. It is very important to choose &amp;quot;Disconnect users in
database&amp;hellip;&amp;quot;. If you don&amp;#39;t do this and by any chance
Management Studio is open on the database on secondary server, log
shipping will keep on failing. So, force disconnect of all users
when database backup is being restored.&lt;/p&gt;
&lt;p&gt;47. Setup a Monitor Server which will automatically take care of
making secondary server the primary server when your primary server
will crash.&lt;/p&gt;
&lt;p&gt;48. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0186.png" width="412" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;49. In the end, the transaction log shipping configuration
window should look like this:&lt;/p&gt;
&lt;p&gt;50. 
&lt;img height="388" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0196.png" width="432" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;51. When you press OK, you will see this:&lt;/p&gt;
&lt;p&gt;
&lt;img height="188" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0216.jpg" width="389" alt="" /&gt;
&lt;/p&gt;
&lt;p&gt;52. Do not be happy at all if you see everything shows
&amp;quot;Success&amp;quot;. Even if you did all the paths, and settings wrong, you
will still see it as successful. Login to the secondary server, go
to SQL Agents-&amp;gt;Jobs and find the Log Ship restore job. If the
job is not there, your configuration was wrong. If it&amp;#39;s there,
right click and select &amp;quot;View History&amp;quot;. Wait for 15 mins to have one
log ship done. Then refresh and see the list. If you see all OK,
then it is really ok. If not, then there are two possibilities:&lt;/p&gt;
&lt;p&gt;a. See if the Log Ship Copy job failed or not. If it fails, then
you entered incorrect path. There can be one of the following
problem:&lt;/p&gt;
&lt;div style="margin-left:4em;"&gt;
&lt;ol&gt;
&lt;li&gt;The network location on primary server is wrong&lt;/li&gt;
&lt;li&gt;The local folder was specified wrong&lt;/li&gt;
&lt;li&gt;You did not set SyncAccount as the account which runs SQL Agent
or you did but forgot to restart the service.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;p&gt;b. If restore fails, then the problems can be one of the
following:&lt;/p&gt;
&lt;p&gt;i. SyncAccount is not a valid login in SQL Server. From SQL
Server Management Studio, add SyncAccount as a user.&lt;/p&gt;
&lt;p&gt;ii. You forgot to restore the database on secondary server as
Standby.&lt;/p&gt;
&lt;p&gt;iii. You probably took some manual transaction log backup on the
primary server in the meantime. As a result, the backup that log
shipping took was not the right sequence.&lt;/p&gt;
&lt;p&gt;53. If everything&amp;#39;s ok, you will see this:&lt;/p&gt;
&lt;p&gt;
&lt;img height="365" src="http://omar.mvps.org/images/HowtosetupSQLServer2005TransactionLogShi_E0B5/clip_image0236.jpg" width="418" alt="" /&gt;
&lt;/p&gt;
&lt;img src="http://msmvps.com/aggbug.aspx?PostID=128439" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/omar/archive/tags/sql+server/default.aspx">sql server</category></item></channel></rss>