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

<channel>
	<title>geniiius.com</title>
	<atom:link href="http://www.geniiius.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.geniiius.com</link>
	<description>i-catching solutions</description>
	<lastBuildDate>Tue, 15 May 2012 16:01:39 +0000</lastBuildDate>
	<language>da</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Backup compression using IBM TDP for SQL Server</title>
		<link>http://www.geniiius.com/blog/backup-compression-using-ibm-tdp-for-sql-server/</link>
		<comments>http://www.geniiius.com/blog/backup-compression-using-ibm-tdp-for-sql-server/#comments</comments>
		<pubDate>Tue, 15 May 2012 08:00:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Performance optimization]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[BACKUP]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=1146</guid>
		<description><![CDATA[If you are using SQL Server 2008 enterprise/datacenter edition, or SQL Server 2008 R2 standard or above, you are in the lucky possition to be able to compress your SQL Server backups. Often I see installations of these versions, where compression is not enabled. Let me show you a couple of ways to do that...]]></description>
			<content:encoded><![CDATA[<p>If you are using SQL Server 2008 enterprise/datacenter edition, or SQL Server 2008 R2 standard or above, you are in the lucky possition to be able to compress your SQL Server backups. Often I see installations of these versions, where compression is not enabled. Let me show you a couple of ways to do that using the built-in backup features.</p>
<h2>Command line</h2>
<p>I have a test database called TPCH, and these are the scripts to perform a full backup without compression, and one with compression:</p>
<pre class="code"><span style="color: green;">--Backup without compression </span>
<span style="color: blue;">BACKUP DATABASE </span><span style="color: teal;">[TPCH] </span><span style="color: blue;">TO DISK </span><span style="color: gray;">= </span><span style="color: red;">'c:\SQLBackup\TPCH_uncompressed.bak'
</span><span style="color: blue;">GO </span>

<span style="color: green;">--Backup with compression </span>
<span style="color: blue;">BACKUP DATABASE </span><span style="color: teal;">[TPCH] </span><span style="color: blue;">TO DISK </span><span style="color: gray;">= </span><span style="color: red;">'c:\SQLBackup\TPCH_compressed.bak' </span><span style="color: blue;">
WITH COMPRESSION
GO </span></pre>
<p>To see the difference, I can look in msdb.dbo.backupset, which shows you both the backup_size without compression, as well as the compressed_backup_size:</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: teal;">
database_name</span><span style="color: gray;">, </span><span style="color: teal;">
backup_size</span><span style="color: gray;">, </span><span style="color: teal;">
compressed_backup_size</span><span style="color: gray;">,
 (</span><span style="color: teal;">backup_size</span><span style="color: gray;">-</span><span style="color: teal;">compressed_backup_size</span><span style="color: gray;">)/</span><span style="color: teal;">backup_size</span><span style="color: gray;">*</span>100 <span style="color: blue;">AS </span><span style="color: teal;">SavingsInPercent </span><span style="color: blue;">
FROM </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: teal;">backupset </span></pre>
<p>The output from this is:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image79.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb78.png" alt="image" width="518" height="107" border="0" /></a></p>
<p>My first backup show the same value in both backup_size and compressed_backup_size columns, and that is because bacup compression wasn’t enabled. The second one shows two different values, and a calculated saving of 58%. This value varies depending on the content of the database, but it’s not uncommon to see savings in the 80-85% area. Not bad, considering the small effort for enabling it <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile16.png" alt="Smiley" /></p>
<h2>GUI</h2>
<p>If you are using the GUI to take a manual backup, you will see the standard backup windows. If you go to the Options pane, you will see this:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image80.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb79.png" alt="image" width="691" height="622" border="0" /></a></p>
<p>Notice the compression part in the bottom. The default setting is “Use the default server setting”, which is “Do not compress backup”. You can select the “Compress backup”, and achieve the same result as with the “WITH COMPRESSION” in the t-sql script. But hey! If there is a “use the default server setting” option, then how can we change that? Simply right click the sql server, go to properties and open up the “Database Settings” tab:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image81.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb80.png" alt="image" width="587" height="466" border="0" /></a></p>
<p>Here you see the “Compress backup” checkbox. If you tick this, the backup’s will automatically be compressed, unless you specifically choose not to perform compression. Pretty nifty!</p>
<h2>IBM TDP for SQL Server</h2>
<p>If you are using IBM Tivoli Data Protection for SQL Server to perform your database backups, the default server setting above is unfortunately ignored. But if you are running TDP 5.5.4 or newer, you can actually enable it anyways. TDP for SQL Server ususally has the following root directory: c:\progra~1\Tivoli\TSM\TDPSql\ and in here you find TDPSql.cfg. In this file you simply add this line to the bottom:</p>
<p>SQLCOMPression          YES</p>
<p>Now restart your scheduler service, and you are good to go. If you would like to verify your own savings after enabling this, you can use the script from before.</p>
<h2>Benefits</h2>
<p>There are a few things worth mentioning. If you enable backup compression, you put extra load on the SQL Server cpu, because it needs to perform the compression. But at the same time you offload your network, because you only need to transfer 15-50% of your usual data volume. And with smaller backups you have room to hold more backups on your storage system.</p>
<p>Depending on your setup, the backup and restore speed will probably be a lot better as well. The backups will be faster because you need to transfer and write less data to your destination. And restores will be faster because you need to read and transfer less data from your backup source.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/backup-compression-using-ibm-tdp-for-sql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Troubleshooting Database mail</title>
		<link>http://www.geniiius.com/blog/troubleshooting-database-mail/</link>
		<comments>http://www.geniiius.com/blog/troubleshooting-database-mail/#comments</comments>
		<pubDate>Tue, 08 May 2012 10:00:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[Database Mail]]></category>
		<category><![CDATA[debugging]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=1121</guid>
		<description><![CDATA[Last week we blogged about “How to configure Database mail” – this week we’ll have a closer look at what to do when everything looks fine, but no mail is flying through the system – what is wrong?. After testing, if you are unable to receive notification emails, you could use the below Database Mail...]]></description>
			<content:encoded><![CDATA[<p>Last week we blogged about “<a href="http://www.geniiius.com/blog/how-to-configure-database-mail/" target="_blank">How to configure Database mail</a>” – this week we’ll have a closer look at what to do when everything looks fine, but no mail is flying through the system – what is wrong?.</p>
<p>After testing, if you are unable to receive notification emails, you could use the below Database Mail views for troubleshooting. This first one contains one single row for each message successfully sent by Database Mail.</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: gray;">* </span><span style="color: blue;">from </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: green;">sysmail_sentitems </span></pre>
<p>This next is the complete opposite, here we’ll se a row for each message with an unsent or retrying status.</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: gray;">* </span><span style="color: blue;">from </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: green;">sysmail_unsentitems </span></pre>
<p>And finally here a view that shows one row for each Database mail message with status failed</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: gray;">* </span><span style="color: blue;">from </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: green;">sysmail_faileditems </span></pre>
<p>Personally I’m not a big fan of the GUI, if You share that passion with me, here is a view that will give You the Database Mail event log.</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: gray;">* </span><span style="color: blue;">from </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: green;">sysmail_event_log </span></pre>
<p>And finally, here is the view that shows it all.</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: gray;">* </span><span style="color: blue;">from </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: green;">sysmail_allitems </span></pre>
<p>Database Mail has two queues, a status queue and a mail queue. The mail queue tells us the number of mail in queue waiting to be sent. The status queue stores the status of items that have already been sent. Here is a Stored Procedure that can show You the status of the two queues.</p>
<pre class="code"><span style="color: blue;">exec </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: maroon;">sysmail_help_queue_sp</span><span style="color: gray;">; </span><span style="color: blue;">exec </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: maroon;">sysmail_help_queue_sp </span><span style="color: teal;">@queue_type </span><span style="color: gray;">= </span><span style="color: red;">'mail'</span><span style="color: gray;">; </span><span style="color: blue;">exec </span><span style="color: teal;">msdb</span><span style="color: gray;">.</span><span style="color: teal;">dbo</span><span style="color: gray;">.</span><span style="color: maroon;">sysmail_help_queue_sp </span><span style="color: teal;">@queue_type </span><span style="color: gray;">= </span><span style="color: red;">'status'</span><span style="color: gray;">; </span></pre>
<p>Did this not help You? Well here is a link to the <a href="http://msdn.microsoft.com/en-us/library/ms188663.aspx" target="_blank">official Microsoft documentation</a>, that might help – happy troubleshooting.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/troubleshooting-database-mail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Configure Database mail</title>
		<link>http://www.geniiius.com/blog/how-to-configure-database-mail/</link>
		<comments>http://www.geniiius.com/blog/how-to-configure-database-mail/#comments</comments>
		<pubDate>Tue, 01 May 2012 06:00:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Geniiius]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[Database Mail]]></category>
		<category><![CDATA[T-SQL]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=1115</guid>
		<description><![CDATA[In my daily job as a SQL Server consultant I go to a lot of places, many days on the road, and many nights at different hotels. All these things are a part of the job, so of course I am not complaining. What some times can be a challenge is to have access to...]]></description>
			<content:encoded><![CDATA[<p>In my daily job as a SQL Server consultant I go to a lot of places, many days on the road, and many nights at different hotels. All these things are a part of the job, so of course I am not complaining.</p>
<p>What some times can be a challenge is to have access to the same SMTP server again and again, and especially when I am testing something with Database Mail, SQL Server alerts, Operators or something else that uses a SMTP server from SQL Server to send out an email.</p>
<p>Because of these challenges I normally use a Gmail account to send mails from, Gmail requires authentication to send mails via their SMTP servers, so an account type like this can be used from anywhere.</p>
<p>So many people have blogged about this before me, including myself actually – I blogged some thing like this a few years back – in DANISH. I always struggle to find my script to configure these things, so that is why I am blogging about this again – to refresh my brain, and to share my code with You. </p>
<p>Before we can start playing with Database mail, we have to enable the feature, that is done with the following code:</p>
<pre class="code"><span style="color: blue">EXEC </span><span style="color: maroon">sp_Configure </span><span style="color: red">'Database Mail XPs'</span><span style="color: gray">, </span>1
<span style="color: blue">GO

RECONFIGURE
GO
</span></pre>
<p>&nbsp;</p>
<p>With the feature enabled, all there is left to do before sending mails from SQL Server, is to changes the following script so that is takes you account info, and not the bogus info that I have entered:</p>
<pre class="code"><span style="color: green">-- Create a Database Mail account
</span><span style="color: blue">EXEC </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_add_account_sp
      </span><span style="color: teal">@account_name </span><span style="color: gray">= </span><span style="color: red">'MyMailAccount'
    </span><span style="color: gray">, </span><span style="color: teal">@email_address </span><span style="color: gray">= </span><span style="color: red">'me@gmail.com'
    </span><span style="color: gray">, </span><span style="color: teal">@display_name </span><span style="color: gray">= </span><span style="color: red">'My Servers Database Mail Account'
    </span><span style="color: gray">, </span><span style="color: teal">@description </span><span style="color: gray">= </span><span style="color: red">'MyMailAccount'
    </span><span style="color: gray">, </span><span style="color: teal">@mailserver_name </span><span style="color: gray">= </span><span style="color: red">'smtp.gmail.com'
    </span><span style="color: gray">, </span><span style="color: teal">@port </span><span style="color: gray">= </span>587
    <span style="color: gray">, </span><span style="color: teal">@username </span><span style="color: gray">= </span><span style="color: red">'me@gmail.com'
    </span><span style="color: gray">, </span><span style="color: teal">@password </span><span style="color: gray">= </span><span style="color: red">'mYpASSWORD'
    </span><span style="color: gray">, </span><span style="color: teal">@enable_ssl </span><span style="color: gray">= </span>1

<span style="color: green">-- Create a Database Mail profile
</span><span style="color: blue">EXECUTE </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_add_profile_sp
    </span><span style="color: teal">@profile_name </span><span style="color: gray">= </span><span style="color: red">'MyPublicProfile'</span><span style="color: gray">,
    </span><span style="color: teal">@description </span><span style="color: gray">= </span><span style="color: red">'My Public Profile'</span><span style="color: gray">;

</span><span style="color: green">-- Add the account to the profile
</span><span style="color: blue">EXECUTE </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_add_profileaccount_sp
    </span><span style="color: teal">@profile_name </span><span style="color: gray">= </span><span style="color: red">'MyPublicProfile'</span><span style="color: gray">,
    </span><span style="color: teal">@account_name </span><span style="color: gray">= </span><span style="color: red">'MyMailAccount'</span><span style="color: gray">,
    </span><span style="color: teal">@sequence_number </span><span style="color: gray">= </span>1<span style="color: gray">;

</span><span style="color: green">-- Configuring global profile, and setting default mail profile
</span><span style="color: blue">EXECUTE </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_add_principalprofile_sp
    </span><span style="color: teal">@profile_name </span><span style="color: gray">= </span><span style="color: red">'MyPublicProfile'</span><span style="color: gray">,
    </span><span style="color: teal">@principal_name </span><span style="color: gray">= </span><span style="color: red">'public'</span><span style="color: gray">,
    </span><span style="color: teal">@is_default </span><span style="color: gray">= </span>1<span style="color: gray">;
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>After execution this script, we are ready to send out an test mail, to check that everything is working, here is the code to do that:</p>
<pre class="code"><span style="color: blue">EXECUTE </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sp_send_dbmail
    </span><span style="color: teal">@subject </span><span style="color: gray">= </span><span style="color: red">'Test Database Mail Message'</span><span style="color: gray">,
    </span><span style="color: teal">@recipients </span><span style="color: gray">= </span><span style="color: red">'me@myemail.com'</span><span style="color: gray">,
    </span><span style="color: teal">@query </span><span style="color: gray">= </span><span style="color: red">'set nocount on;SELECT Getdate() as ServerTime'</span><span style="color: gray">;
</span></pre>
<p>&nbsp;</p>
<p>Wait one second and you should receive an email from you SQL Server. In the next blog post we’ll look at how to monitor and debug Database mail – stay tuned for that next week.</p>
<p>Before I finish this blog post totally, I’ll just show you a few functions and views that you can use to look at the profiles and accounts created. And another god thing to have handy is how to delete the account/profile just created.</p>
<pre class="code"><span style="color: blue">exec </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_delete_account_sp </span><span style="color: teal">@account_name </span><span style="color: gray">= </span><span style="color: red">'MyMailAccount'
</span><span style="color: blue">exec </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: maroon">sysmail_delete_profile_sp </span><span style="color: teal">@profile_name </span><span style="color: gray">= </span><span style="color: red">'MyPublicProfile'

</span><span style="color: blue">select </span><span style="color: gray">* </span><span style="color: blue">from </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: teal">sysmail_account
</span><span style="color: blue">select </span><span style="color: gray">* </span><span style="color: blue">from </span><span style="color: teal">msdb</span><span style="color: gray">.</span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: teal">sysmail_profile
</span></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/how-to-configure-database-mail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automatic page repair with SQL Server Mirroring</title>
		<link>http://www.geniiius.com/blog/automatic-page-repair-with-sql-server-mirroring/</link>
		<comments>http://www.geniiius.com/blog/automatic-page-repair-with-sql-server-mirroring/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 17:14:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[SQL Server; SQL Server mirroring]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=1111</guid>
		<description><![CDATA[Now and then my colleagues and I find our selves in the middle of a discussion about SQL Server Mirroring versus the more traditional Failover Clustering. Both are features provided by SQL Server for achieving high availability, buth they both have pro’s and con’s that could make a decision hard. It’s most often these pro’s...]]></description>
			<content:encoded><![CDATA[<p>Now and then my colleagues and I find our selves in the middle of a discussion about SQL Server Mirroring versus the more traditional Failover Clustering. Both are features provided by SQL Server for achieving high availability, buth they both have pro’s and con’s that could make a decision hard. It’s most often these pro’s and con’s we are discussing for different setups.</p>
<p>One of the features that mirroring gives us, almost never make it to our discussions. And since this feature is actually pretty nice and powerful, I thought it was worth sharing – and perhaps we will remember to take it into account the next time we battle about HA <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile15.png" alt="Smiley" /><br />
The feature is called “Automatic Page Repair”, and is documented here: <a href="http://msdn.microsoft.com/en-us/library/bb677167.aspx">http://msdn.microsoft.com/en-us/library/bb677167.aspx</a></p>
<p>If a page corruption has been detected on the prinical server, it can automatically read that specific page from the mirror database and fix the principal. How cool is that?!&#8221; Using a failover cluster, the database files are only located in one location, and if something happens with the underlying storage system corrupting your data, the only way of fixing it is to restore a backup as soon as possible after you identify the corruption. No need to say, that this is not optimal.</p>
<p><strong>Demo</strong></p>
<p>To show you how this works, I have created a mirror between two local instances on my computer. I won’t go into details about the creation of the mirror, but now I have this on my computer:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image75.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb74.png" alt="image" width="377" height="332" border="0" /></a></p>
<p>The mirrored database is MyData, and sqlmaster\sql2008 instance is currently the principal.</p>
<p>I created a dummy table using this script:</p>
<pre class="code"><span style="color: blue;">use </span><span style="color: teal;">MyData </span><span style="color: blue;">go create table </span><span style="color: teal;">TestData </span><span style="color: gray;">(</span><span style="color: teal;">id </span><span style="color: blue;">int identity</span><span style="color: gray;">, </span><span style="color: teal;">col1 </span><span style="color: blue;">char</span><span style="color: gray;">(</span>2000<span style="color: gray;">)) </span><span style="color: blue;">go insert into </span><span style="color: teal;">TestData </span><span style="color: gray;">(</span><span style="color: teal;">col1</span><span style="color: gray;">) </span><span style="color: blue;">values </span><span style="color: gray;">(</span><span style="color: magenta;">replicate</span><span style="color: gray;">(</span><span style="color: red;">'a'</span><span style="color: gray;">, </span>2000<span style="color: gray;">)) </span><span style="color: blue;">go </span>4096</pre>
<p>Now I will simulate a disk failure on the sqlmaster\sql2008 server, so I stop the service and open the .mdf file in a hex editor. Somewhere down the file, this show up:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image76.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb75.png" alt="image" width="698" height="478" border="0" /></a></p>
<p>All the a’s are the data column, and the part in the middle is probably a page header. The details are not important for this test, but I’ll replace a bunch of the data with zeros:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image77.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb76.png" alt="image" width="667" height="432" border="0" /></a></p>
<p>Save the file, and start up the sql server.</p>
<p>Now I perform a table scan by simply issuing a select * from… and this is what happens:</p>
<p><span style="color: #ff0000;">Msg 824, Level 24, State 2, Line 1 SQL Server detected a logical consistency-based I/O error: incorrect </span><span style="color: #ff0000;">checksum (expected: 0xb4f55a1a; actual: 0xa4a264f1). It occurred during </span><span style="color: #ff0000;">a read of <strong>page (1:840)</strong> in database ID 5 at offset 0&#215;00000000690000 in </span><span style="color: #ff0000;">file &#8216;C:\DemoData\MyData.mdf&#8217;. </span><span style="color: #ff0000;">Additional messages in the SQL Server error log or system event log may provide </span><span style="color: #ff0000;">more detail. This is a severe error condition that threatens database integrity </span><span style="color: #ff0000;">and must be corrected immediately. Complete a full database consistency check </span><span style="color: #ff0000;">(DBCC CHECKDB). This error can be caused by many factors; for more information, </span><span style="color: #ff0000;">see SQL Server Books Online. </span></p>
<p>That is a message we normally don’t want to see. It states that page 840 is corrupt, but because the database is part of a mirror, some cool magic has happened. If I run the select again, I get a similar error – but this time for page 841. And third time I execute the select *, it succeeds! What has happened is the “Automatic Page Repair” mechanism kicking in. SQL Server provides a DMV called <a href="http://msdn.microsoft.com/en-us/library/bb677259.aspx">sys.dm_db_mirroring_auto_page_repair</a> to see if repairs like that have happened, so let’s have a look at that:</p>
<pre class="code"><span style="color: blue;">SELECT </span><span style="color: magenta;">DB_NAME</span><span style="color: gray;">(</span><span style="color: teal;">database_id</span><span style="color: gray;">) </span><span style="color: blue;">as </span><span style="color: teal;">DatabaseName</span><span style="color: gray;">, * </span><span style="color: blue;">FROM </span><span style="color: green;">sys</span><span style="color: gray;">.</span><span style="color: green;">dm_db_mirroring_auto_page_repair</span><span style="color: gray;">; </span></pre>
<p><a href="http://www.geniiius.com/wp-content/uploads/image78.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb77.png" alt="image" width="667" height="98" border="0" /></a></p>
<p>Here we can actually see that page_id 840 and 841 were repaired automatically.<br />
The automatic page repair feature does not prevent an error to occur, but when a query tries to access a corrupt page, it will be repaired automatically so it is ready to use for the next query. So the impact of disk errors will be limited.<br />
If you are using mirroring in your setup, try to have a look at this DMV. If a lot of errors show up here, it might be an indication of bad disks, and you should take action to fix it.</p>
<p>So if you find yourself needing arguments in favor of mirroring, this is a feature worth remembering.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/automatic-page-repair-with-sql-server-mirroring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visualize Wait stats with Microsoft Excel</title>
		<link>http://www.geniiius.com/blog/visualize-wait-stats-with-microsoft-excel/</link>
		<comments>http://www.geniiius.com/blog/visualize-wait-stats-with-microsoft-excel/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 16:37:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[DMV]]></category>
		<category><![CDATA[Performance optimization]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQL Server 2012]]></category>
		<category><![CDATA[Wait Stats]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[WaitStats]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=1063</guid>
		<description><![CDATA[In our blog post last week: Instance Wide Wait Stats we promised to show You how to visualize the collected wait stats with Microsoft Excel, so this is what this blog post will be about. The blog post from last week will be the basic setup for this one, so the steps to create the...]]></description>
			<content:encoded><![CDATA[<p>In our blog post last week: <a href="http://www.geniiius.com/blog/instance-wide-wait-stats/" target="_blank">Instance Wide Wait Stats</a> we promised to show You how to visualize the collected wait stats with Microsoft Excel, so this is what this blog post will be about. </p>
<p>The blog post from last week will be the basic setup for this one, so the steps to create the table and to collect the data will not be repeated in this one. If you need them you’ll have to go back and get it.</p>
<p>Today I’ll encapsulate the TSQL logic in a view, this is not necessary, but it makes it much easier from Excel to connect to a predefined view rather than having to write the TSQL. I will call the view for V_WaitStats, and here is the code to create it:</p>
<pre class="code"><span style="color: blue">CREATE VIEW </span><span style="color: teal">V_WaitStats
</span><span style="color: blue">AS

WITH </span><span style="color: teal">cte </span><span style="color: blue">AS
</span><span style="color: gray">(
</span><span style="color: blue">SELECT
    </span><span style="color: teal">id</span><span style="color: gray">, </span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">SampleTime</span><span style="color: gray">,
    </span><span style="color: magenta">ROW_NUMBER</span><span style="color: gray">() </span><span style="color: blue">OVER</span><span style="color: gray">(</span><span style="color: blue">PARTITION BY </span><span style="color: teal">wait_type </span><span style="color: blue">ORDER BY </span><span style="color: teal">SampleTime</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">rn
</span><span style="color: blue">FROM </span><span style="color: teal">InstanceWideWaitStats
</span><span style="color: gray">)
</span><span style="color: blue">SELECT
 </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">,
 </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">- </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: blue">as </span><span style="color: teal">WaitTimeInMS</span><span style="color: gray">,
 </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">SampleTime
</span><span style="color: blue">FROM </span><span style="color: teal">cte t1
</span><span style="color: gray">INNER JOIN </span><span style="color: teal">cte t2 </span><span style="color: blue">on </span><span style="color: gray">(</span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_type </span><span style="color: gray">= </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">) and (</span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">rn </span><span style="color: gray">= </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">rn </span><span style="color: gray">-</span>1<span style="color: gray">)
</span><span style="color: blue">WHERE </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">- </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">&lt;&gt; </span>0
</pre>
<p>&nbsp;</p>
<p>What I want to do next is connect to my SQL Server View from Excel, I am no way an Excel Guru, but this is so easy, and such a powerful tool at visualize data like wait stats. Here is some screenshots from the process.</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image70.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb69.png" width="375" height="265"></a></p>
<p>First step is to enter the name of the SQL Server where the data is stored</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image71.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb70.png" width="385" height="275"></a></p>
<p>Then is it time to select database and the View that we created earlier in this blog post. And the in the end it is just a matter of choosing the right option.</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image72.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb71.png" width="244" height="219"></a></p>
<p>And then just hit the OK button. Then it is time to show some Pivot Table magic, Excel gives us <strong>so</strong> many opportunities to play around with the Wait Stats data, further down you’ll find some examples that shows some of them. Selecting a subset of wait types or periods is easy with Excel, and the Graph changes straight away.</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image73.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb72.png" width="460" height="228"></a></p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image74.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb73.png" width="465" height="229"></a></p>
<p>I use this quite often, and the information that You get with this is very useful. This solution that we have described in these two blog posts, should be in every DBA’s toolbox.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/visualize-wait-stats-with-microsoft-excel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instance Wide Wait Stats</title>
		<link>http://www.geniiius.com/blog/instance-wide-wait-stats/</link>
		<comments>http://www.geniiius.com/blog/instance-wide-wait-stats/#comments</comments>
		<pubDate>Mon, 09 Apr 2012 10:00:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Geniiius]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=994</guid>
		<description><![CDATA[Over the last many weeks we have written quite a few blog post about query debugging, using Extended Events, Blocking sampling and other techniques. Today we are taking a few steps back, and demonstrate how you could start looking at performance problems on a system that you don’t know anything about. One of the first...]]></description>
			<content:encoded><![CDATA[<p>Over the last many weeks we have written quite a few blog post about query debugging, using Extended Events, Blocking sampling and other techniques. Today we are taking a few steps back, and demonstrate how you could start looking at performance problems on a system that you don’t know anything about.</p>
<p>One of the first things that I always start looking at is wait stats, by looking at a systems wait statistics I get a quick idea about where to start looking next – is it IO (Slow IO Sub system or missing indexes), is it memory or something complete different. To do this I use <a href="http://msdn.microsoft.com/en-us/library/ms179984.aspx" target="_blank">sys.dm_os_wait_stats</a>, this gives me instance wide wait stats, accumulated since SQL Server was last restarted or since the stats was cleared. You can read more about the <a href="http://msdn.microsoft.com/en-us/library/ms179984.aspx" target="_blank">sys.dm_os_wait_stats</a> DMV <a href="http://msdn.microsoft.com/en-us/library/ms179984.aspx" target="_blank">here</a>.</p>
<p>Looking at the raw output from sys.dm_os_wait_stats doesn&#8217;t give you much to work with, you need to apply some kind of black magic. I am not going to take the credits for the following script, it comes from a blog that belongs to guy called <a href="http://sqlserverperformance.wordpress.com/" target="_blank">Glen Berry</a>. Glen publishes a collection of scripts every months that are very useful. Here is the magic:</p>
<pre class="code"><span style="color: blue">WITH </span><span style="color: teal">Waits </span><span style="color: blue">AS </span><span style="color: gray">(
</span><span style="color: blue">SELECT </span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">wait_time_ms </span><span style="color: gray">/ </span>1000. <span style="color: blue">AS </span><span style="color: teal">wait_time_s</span><span style="color: gray">,
    </span>100. <span style="color: gray">* </span><span style="color: teal">wait_time_ms </span><span style="color: gray">/ </span><span style="color: magenta">SUM</span><span style="color: gray">(</span><span style="color: teal">wait_time_ms</span><span style="color: gray">) </span><span style="color: blue">OVER</span><span style="color: gray">() </span><span style="color: blue">AS </span><span style="color: teal">pct</span><span style="color: gray">,
    </span><span style="color: magenta">ROW_NUMBER</span><span style="color: gray">() </span><span style="color: blue">OVER</span><span style="color: gray">(</span><span style="color: blue">ORDER BY </span><span style="color: teal">wait_time_ms </span><span style="color: blue">DESC</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">rn
 </span><span style="color: blue">FROM </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_os_wait_stats
 </span><span style="color: blue">WHERE </span><span style="color: teal">wait_type </span><span style="color: gray">NOT IN(</span><span style="color: red">'KSOURCE_WAKEUP'</span><span style="color: gray">, </span><span style="color: red">'SLEEP_BPOOL_FLUSH'</span><span style="color: gray">, </span><span style="color: red">'BROKER_TASK_STOP'</span><span style="color: gray">,
 </span><span style="color: red">'XE_TIMER_EVENT'</span><span style="color: gray">, </span><span style="color: red">'XE_DISPATCHER_WAIT'</span><span style="color: gray">, </span><span style="color: red">'FT_IFTS_SCHEDULER_IDLE_WAIT'</span><span style="color: gray">,
 </span><span style="color: red">'SQLTRACE_BUFFER_FLUSH'</span><span style="color: gray">, </span><span style="color: red">'CLR_AUTO_EVENT'</span><span style="color: gray">, </span><span style="color: red">'BROKER_EVENTHANDLER'</span><span style="color: gray">, </span><span style="color: red">'LAZYWRITER_SLEEP'</span><span style="color: gray">,
 </span><span style="color: red">'BAD_PAGE_PROCESS'</span><span style="color: gray">, </span><span style="color: red">'BROKER_TRANSMITTER'</span><span style="color: gray">, </span><span style="color: red">'CHECKPOINT_QUEUE'</span><span style="color: gray">, </span><span style="color: red">'DBMIRROR_EVENTS_QUEUE'</span><span style="color: gray">,
 </span><span style="color: red">'LAZYWRITER_SLEEP'</span><span style="color: gray">, </span><span style="color: red">'ONDEMAND_TASK_QUEUE'</span><span style="color: gray">, </span><span style="color: red">'REQUEST_FOR_DEADLOCK_SEARCH'</span><span style="color: gray">, </span><span style="color: red">'LOGMGR_QUEUE'</span><span style="color: gray">,
 </span><span style="color: red">'SLEEP_TASK'</span><span style="color: gray">, </span><span style="color: red">'SQLTRACE_BUFFER_FLUSH'</span><span style="color: gray">, </span><span style="color: red">'CLR_MANUAL_EVENT'</span><span style="color: gray">, </span><span style="color: red">'BROKER_RECEIVE_WAITFOR'</span><span style="color: gray">,
 </span><span style="color: red">'PREEMPTIVE_OS_GETPROCADDRESS'</span><span style="color: gray">, </span><span style="color: red">'PREEMPTIVE_OS_AUTHENTICATIONOPS'</span><span style="color: gray">, </span><span style="color: red">'BROKER_TO_FLUSH'</span><span style="color: gray">)
 )
</span><span style="color: blue">SELECT </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">,
  </span><span style="color: magenta">CAST</span><span style="color: gray">(</span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">wait_time_s </span><span style="color: blue">AS DECIMAL</span><span style="color: gray">(</span>12<span style="color: gray">, </span>2<span style="color: gray">)) </span><span style="color: blue">AS </span><span style="color: teal">wait_time_s</span><span style="color: gray">,
  </span><span style="color: magenta">CAST</span><span style="color: gray">(</span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">pct </span><span style="color: blue">AS DECIMAL</span><span style="color: gray">(</span>12<span style="color: gray">, </span>2<span style="color: gray">)) </span><span style="color: blue">AS </span><span style="color: teal">pct</span><span style="color: gray">,
  </span><span style="color: magenta">CAST</span><span style="color: gray">(</span><span style="color: magenta">SUM</span><span style="color: gray">(</span><span style="color: teal">W2</span><span style="color: gray">.</span><span style="color: teal">pct</span><span style="color: gray">) </span><span style="color: blue">AS DECIMAL</span><span style="color: gray">(</span>12<span style="color: gray">, </span>2<span style="color: gray">)) </span><span style="color: blue">AS </span><span style="color: teal">running_pct
</span><span style="color: blue">FROM </span><span style="color: teal">Waits </span><span style="color: blue">AS </span><span style="color: teal">W1
</span><span style="color: gray">INNER JOIN </span><span style="color: teal">Waits </span><span style="color: blue">AS </span><span style="color: teal">W2 </span><span style="color: blue">ON </span><span style="color: teal">W2</span><span style="color: gray">.</span><span style="color: teal">rn </span><span style="color: gray">&lt;= </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">rn
</span><span style="color: blue">GROUP BY </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">rn</span><span style="color: gray">, </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">wait_time_s</span><span style="color: gray">, </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">pct
</span><span style="color: blue">HAVING </span><span style="color: magenta">SUM</span><span style="color: gray">(</span><span style="color: teal">W2</span><span style="color: gray">.</span><span style="color: teal">pct</span><span style="color: gray">) - </span><span style="color: teal">W1</span><span style="color: gray">.</span><span style="color: teal">pct </span><span style="color: gray">&lt; </span>95<span style="color: gray">;
</span></pre>
<p>&nbsp;</p>
<p>and if we take a look at the output that this script gives on my no-action laptop, it look like this:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image68.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb67.png" width="427" height="101"></a></p>
<p>the wait types that you see here is more or less useless, there is no SQL Server activity on my laptop, but try running the script on your system, and hopefully you’ll se something way different.</p>
<p>To get more info about Wait Types, and what they mean to your system, here is an excellent link that explains that in <a href="http://blogs.msdn.com/b/psssql/archive/2009/11/03/the-sql-server-wait-type-repository.aspx" target="_blank">detail</a>.</p>
<p><strong>Wait stats over time</strong></p>
<p>The above example show how you can look at wait stats here and now, but how about the user that calls You Monday morning and complains about poor performance during the weekend – the above script is not really going to help you with that. I a situation like that is would be really nice with wait stat information from the weekend, even better if they could be broken down into small timeslots. If you could see the change in the wait stats between 11:00 and 11:15 that might give you an idea where to start to look for the problems.</p>
<p>Lets try to build a solution that makes such information available for you. First off all, I will create a table to store the sample data in.</p>
<pre class="code"><span style="color: blue">Create table </span><span style="color: teal">InstanceWideWaitStats
</span><span style="color: gray">(
    </span><span style="color: teal">id </span><span style="color: blue">bigint identity</span><span style="color: gray">(</span>1<span style="color: gray">,</span>1<span style="color: gray">) </span><span style="color: blue">primary key</span><span style="color: gray">,
    </span><span style="color: teal">wait_type </span><span style="color: blue">nvarchar</span><span style="color: gray">(</span>120<span style="color: gray">),
    </span><span style="color: teal">waiting_tasks_count    </span><span style="color: blue">bigint</span><span style="color: gray">,
    </span><span style="color: teal">wait_time_ms </span><span style="color: blue">bigint</span><span style="color: gray">,
    </span><span style="color: teal">max_wait_time_ms </span><span style="color: blue">bigint</span><span style="color: gray">,
    </span><span style="color: teal">signal_wait_time_ms    </span><span style="color: blue">bigint</span><span style="color: gray">,
    </span><span style="color: teal">SampleTime </span><span style="color: blue">datetime2 default </span><span style="color: magenta">sysdatetime</span><span style="color: gray">()
)
</span></pre>
<p>&nbsp;</p>
<p>Now let’s write some TSQL that writes some data into this table:</p>
<pre class="code"><span style="color: blue">insert into </span><span style="color: teal">InstanceWideWaitStats </span><span style="color: gray">(</span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">waiting_tasks_count</span><span style="color: gray">, </span><span style="color: teal">wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">max_wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">signal_wait_time_ms</span><span style="color: gray">)
</span><span style="color: blue">select
    </span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">waiting_tasks_count</span><span style="color: gray">, </span><span style="color: teal">wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">max_wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">signal_wait_time_ms
</span><span style="color: blue">from </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_os_wait_stats
</span></pre>
<p>&nbsp;</p>
<p>This code is super simple, the only thing that I actually do is to sample the DMV that I mentioned earlier in this blog post. What I normally do it the schedule this to run every 15 minutes with the SQL Server Agent. When that is done we are ready to have a look at the data.</p>
<p>The information that I am interested in is the column called wait_time_ms – the same column from the last sample that we did. This gives me the amount of wait time of a given Wait Type between two samples, which is 15 minutes if You run the job every 15 minutes. Let’s have a look at the TSQL:</p>
<pre class="code"><span style="color: blue">with </span><span style="color: teal">cte </span><span style="color: blue">as
</span><span style="color: gray">(
</span><span style="color: blue">select
    </span><span style="color: teal">id</span><span style="color: gray">, </span><span style="color: teal">wait_type</span><span style="color: gray">, </span><span style="color: teal">wait_time_ms</span><span style="color: gray">, </span><span style="color: teal">SampleTime</span><span style="color: gray">,
    </span><span style="color: magenta">ROW_NUMBER</span><span style="color: gray">() </span><span style="color: blue">OVER</span><span style="color: gray">(</span><span style="color: blue">PArtition by </span><span style="color: teal">wait_type </span><span style="color: blue">order by </span><span style="color: teal">SampleTime</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">rn
</span><span style="color: blue">from </span><span style="color: teal">InstanceWideWaitStats
</span><span style="color: gray">)
</span><span style="color: blue">select
 </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">,
 </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">- </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: blue">as </span><span style="color: teal">WaitTimeInMS</span><span style="color: gray">,
 </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">SampleTime
</span><span style="color: blue">from </span><span style="color: teal">cte t1
</span><span style="color: gray">inner join </span><span style="color: teal">cte t2 </span><span style="color: blue">on </span><span style="color: gray">(</span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_type </span><span style="color: gray">= </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_type</span><span style="color: gray">) and (</span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">rn </span><span style="color: gray">= </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">rn </span><span style="color: gray">-</span>1<span style="color: gray">)
</span><span style="color: blue">where </span><span style="color: teal">t2</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">- </span><span style="color: teal">t1</span><span style="color: gray">.</span><span style="color: teal">wait_time_ms </span><span style="color: gray">&lt;&gt; </span>0
</pre>
<p>&nbsp;</p>
<p>This is SQL Server 2008 syntax, SQL Server 2012 comes with a new feature called LAG / LEAD. If you are running 2012 your code would be much more simple, and could look something like this:</p>
<pre class="code"><span style="color: blue">SELECT
 </span><span style="color: teal">wait_type</span><span style="color: gray">,
 </span><span style="color: teal">SampleTime</span><span style="color: gray">,
 </span><span style="color: teal">wait_time_ms </span><span style="color: gray">- </span><span style="color: teal">LAG</span><span style="color: gray">(</span><span style="color: teal">wait_time_ms</span><span style="color: gray">, </span>1<span style="color: gray">, null) </span><span style="color: blue">OVER</span><span style="color: gray">(</span><span style="color: blue">PArtition by </span><span style="color: teal">wait_type </span><span style="color: blue">order by </span><span style="color: teal">SampleTime</span><span style="color: gray">)
</span><span style="color: blue">FROM </span><span style="color: teal">InstanceWideWaitStats
</span><span style="color: blue">where </span><span style="color: teal">wait_type </span><span style="color: gray">= </span><span style="color: red">'BROKER_TO_FLUSH'
</span></pre>
<p>&nbsp;</p>
<p>In a real world examples you would consider to have a where clauses or something on the SampleTime column, to avoid to get to much data and only to look at the period you need. Let’s have a look at the output from the 2008 syntax query:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image69.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb68.png" width="453" height="100"></a></p>
<p>wuupa, here goes the magic – with this little simple setup we are now able to look at the wait stats and how they looked earlier. As mentioned earlier, this is not a silver bullet, this is just a very good place to start looking when you have performance issues with your SQL Server.</p>
<p>In the next blog post I’ll demonstrate how you can visualize this data, and make it quite nice and easy to look at with Excel.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/instance-wide-wait-stats/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Nifty queries using a Numbers helper table</title>
		<link>http://www.geniiius.com/blog/nifty-queries-using-a-numbers-helper-table/</link>
		<comments>http://www.geniiius.com/blog/nifty-queries-using-a-numbers-helper-table/#comments</comments>
		<pubDate>Wed, 04 Apr 2012 18:39:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[auxiliary numbers table]]></category>
		<category><![CDATA[T-SQL]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=987</guid>
		<description><![CDATA[(The complete usable code is in the very bottom of this blog post) Some of you may have seen this “numbers table” technique in use before, but I thought I would share a few simpel examples to those of you that haven’t seen the light yet Lets start with a classic problem: Converting a delimited...]]></description>
			<content:encoded><![CDATA[<p>(The complete usable code is in the very bottom of this blog post)</p>
<p>Some of you may have seen this “numbers table” technique in use before, but I thought I would share a few simpel examples to those of you that haven’t seen the light yet <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile14.png"></p>
<p>Lets start with a classic problem: Converting a delimited string into a table.</p>
<p>In many old setups I have seen, it’s not uncommon to have the need for passing multiple values to a stored procedure, to look up data for multiple values in one go. Let me build my demo table, and show how such a stored procedure could look like:</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">MyFavoriteMovies
</span><span style="color: gray">(
    </span><span style="color: teal">MovieId </span><span style="color: blue">INT IDENTITY</span><span style="color: gray">(</span>1<span style="color: gray">,</span>1<span style="color: gray">) </span><span style="color: blue">PRIMARY KEY</span><span style="color: gray">,
    </span><span style="color: teal">MovieTitle </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>100<span style="color: gray">),
    </span><span style="color: teal">NumberOfViews </span><span style="color: blue">INT
</span><span style="color: gray">)
</span><span style="color: blue">GO
INSERT INTO </span><span style="color: teal">MyFavoriteMovies </span><span style="color: gray">(</span><span style="color: teal">MovieTitle</span><span style="color: gray">, </span><span style="color: teal">NumberOfViews</span><span style="color: gray">)
</span><span style="color: blue">VALUES
    </span><span style="color: gray">(</span><span style="color: red">'Gone with the Wind'</span><span style="color: gray">, </span>23<span style="color: gray">),
    (</span><span style="color: red">'Driving Miss Daisy'</span><span style="color: gray">, </span>9<span style="color: gray">),
    (</span><span style="color: red">'Martha'</span><span style="color: gray">, </span>16<span style="color: gray">),
    (</span><span style="color: red">'Fætrene på Torndal'</span><span style="color: gray">, </span>33<span style="color: gray">),
    (</span><span style="color: red">'Casablanca'</span><span style="color: gray">, </span>8<span style="color: gray">),
    (</span><span style="color: red">'Dumb &amp; Dumber'</span><span style="color: gray">, </span>6<span style="color: gray">),
    (</span><span style="color: red">'Wargames'</span><span style="color: gray">, </span>24<span style="color: gray">),
    (</span><span style="color: red">'Geniiius, the movie'</span><span style="color: gray">, NULL)
</span><span style="color: blue">GO

CREATE PROCEDURE </span><span style="color: teal">FetchMovieTitles
@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">)
</span><span style="color: blue">AS
DECLARE </span><span style="color: teal">@sqlcmd </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span><span style="color: magenta">MAX</span><span style="color: gray">) = </span><span style="color: red">'
    SELECT * FROM MyFavoriteMovies
    WHERE MovieId IN (' </span><span style="color: gray">+ </span><span style="color: teal">@MovieIds </span><span style="color: gray">+ </span><span style="color: red">')'
</span><span style="color: blue">EXEC </span><span style="color: gray">(</span><span style="color: teal">@sqlcmd</span><span style="color: gray">)
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>I created a table to hold a list of my favorite movies, and then I have a stored procedure i can execute, that takes a comma separated list of MovieId’s as parameter. It’s not pretty, I know, but nevertheless it’s a template I have seen numerous times over the time.</p>
<p>So why is this not ideal?</p>
<p>The obvious reason is, that because the stored procedure generates the sql command dynamically, and then executes it without any check whatsoever, it’s open for sql injections. On top of that security issue, it also generates a new execution plan for every different parameter that the procedure is executed with. If my query was more complex in the procedure, the dynamic sql could easily becomre nasty to work with. Think about the single quote which serves both as the escape character but also surrounds strings. An example of this could look like this:</p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@sqlcmd </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span><span style="color: magenta">MAX</span><span style="color: gray">) = </span><span style="color: red">'
    SELECT * FROM MyFavoriteMovies
    WHERE MovieId IN (' </span><span style="color: gray">+ </span><span style="color: teal">@MovieIds </span><span style="color: gray">+ </span><span style="color: red">')
    AND MovieTitle = ''Wargames'''
</span></pre>
<p>&nbsp;</p>
<p>Ugly, right?</p>
<p>So how can we fix this you ask? Imaging we could convert the list of MovieId’s to a table, then the query could look something like this:</p>
<pre class="code"><span style="color: blue">SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">MyFavoriteMovies
</span><span style="color: blue">WHERE </span><span style="color: teal">MovieId </span><span style="color: gray">IN (</span><span style="color: blue">SELECT </span><span style="color: teal">MovieId </span><span style="color: blue">FROM </span><span style="color: teal">#MovieIds</span><span style="color: gray">)
AND </span><span style="color: teal">MovieTitle </span><span style="color: gray">= </span><span style="color: red">'Wargames'
</span></pre>
<p>&nbsp;</p>
<p>Now we got rid of the dynamic sql, and it’s much prettier to read. But we don’t have the #MovieIds table yet, so we need to find a way to convert our delimited string to a table.</p>
<p>Let’s start to build the solution up, by looking at this:</p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">) = </span><span style="color: red">'1,3,5'
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>1<span style="color: gray">, </span><span style="color: magenta">len</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">))
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>2<span style="color: gray">, </span><span style="color: magenta">len</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">))
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>3<span style="color: gray">, </span><span style="color: magenta">len</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">))
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>4<span style="color: gray">, </span><span style="color: magenta">len</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">))
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>5<span style="color: gray">, </span><span style="color: magenta">len</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">))
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image61.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb60.png" width="153" height="283"></a></p>
<p>Here I have five select statements, which performs a substring on the variable, but with an increasing offset going from 1 to 5. Notice that the length of the @MovieIds string is exactly 5 characters. Does this get my any closer to the solution? Can you spot the pattern? The first character in the first, third and fifth result is actually the values I’m looking for. But how could I identify these? What if we instead of selecting the rest of the string in each of the substring command, could stop at the next comma? </p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">) = </span><span style="color: red">'1,3,5'
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>1<span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span>1<span style="color: gray">) - </span>1<span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>2<span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span>2<span style="color: gray">) - </span>2<span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>3<span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span>3<span style="color: gray">) - </span>3<span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>4<span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span>4<span style="color: gray">) - </span>4<span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span>5<span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span>5<span style="color: gray">) - </span>5<span style="color: gray">)
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image62.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb61.png" width="156" height="280"></a></p>
<p>The length of the substring is now replaced by the CHARINDEX function. Once again notice the pattern with the increasing values from 1 to 5. The result now almost look like what I want. If I could filter out the second and fourth row, and merge the rest into a table – then I’m done. </p>
<p><strong>Enter Numbers table</strong></p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">Numbers </span><span style="color: gray">(
    </span><span style="color: teal">n </span><span style="color: blue">INT PRIMARY KEY
</span><span style="color: gray">)
</span><span style="color: blue">GO
INSERT INTO </span><span style="color: teal">Numbers </span><span style="color: gray">(</span><span style="color: teal">n</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">), (</span>2<span style="color: gray">), (</span>3<span style="color: gray">), (</span>4<span style="color: gray">), (</span>5<span style="color: gray">)
</span><span style="color: blue">GO
SELECT </span><span style="color: teal">n </span><span style="color: blue">FROM </span><span style="color: teal">Numbers
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image63.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb62.png" width="89" height="158"></a></p>
<p>Do you see a pattern that looks like the substring queries above? Now we can actually use the n column from the Numbers table instead of the hardcoded values for the increasing numbers 1 to 5. That would look like this:</p>
<p>&nbsp;</p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">) = </span><span style="color: red">'1,3,5'
</span><span style="color: blue">SELECT    </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: red">','</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">)
</span><span style="color: blue">FROM    </span><span style="color: teal">Numbers

</span></pre>
<p>Now I select from the Numbers table, and the only coulumn I select, is the substring function from before – but now with column n instead of the hardcoded values 1 to 5. The output:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image64.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb63.png" width="177" height="173"></a></p>
<p>&nbsp;</p>
<p>It’s getting warm… we are almost there.</p>
<p>To filter out the rows I don’t want, I need to find something I can use in a where clause. The easiest is to simply use the very same substring line, and the find the rows with a value &lt;&gt; ‘’. That would look like this:
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">) = </span><span style="color: red">'1,3,5'
</span><span style="color: blue">DECLARE </span><span style="color: teal">@Delimiter </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>5<span style="color: gray">) = </span><span style="color: red">','
</span><span style="color: blue">SELECT    </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">MyCol
</span><span style="color: blue">FROM    </span><span style="color: teal">Numbers
</span><span style="color: blue">WHERE    </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">@MovieIds</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">) &lt;&gt; </span><span style="color: red">''
</span></pre>
</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image65.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb64.png" width="129" height="147"></a></p>
<p>This looks very much like what we need. If we put this in a function called dbo.SplitToTable() that takes the parameters @Input and @Delimiter, we can write our original procedure like this:</p>
<pre class="code"><span style="color: blue">CREATE FUNCTION </span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: teal">SplitToTable</span><span style="color: gray">(</span><span style="color: teal">@Input </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">), </span><span style="color: teal">@Delimiter </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>5<span style="color: gray">))
</span><span style="color: blue">RETURNS TABLE
AS RETURN
</span><span style="color: gray">(
</span><span style="color: blue">SELECT    </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@Input</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">@Input</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">val
</span><span style="color: blue">FROM    </span><span style="color: teal">Numbers
</span><span style="color: blue">WHERE    </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@Input</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">@Input</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">) &lt;&gt; </span><span style="color: red">''
</span><span style="color: gray">)
</span><span style="color: blue">GO

ALTER PROCEDURE </span><span style="color: teal">FetchMovieTitles
@MovieIds </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>1000<span style="color: gray">)
</span><span style="color: blue">AS
SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">MyFavoriteMovies
</span><span style="color: blue">WHERE </span><span style="color: teal">MovieId </span><span style="color: gray">IN (</span><span style="color: blue">SELECT <span style="color: magenta">SUBSTRING(</span></span><span style="color: teal">val <span style="color: blue">AS INT<span style="color: gray">)</span></span> </span><span style="color: blue">FROM </span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: teal">SplitToTable</span><span style="color: gray">(</span><span style="color: teal">@MovieIds</span><span style="color: gray">, </span><span style="color: red">','</span><span style="color: gray">))
</span><span style="color: blue">GO

EXEC </span><span style="color: teal">FetchMovieTitles @MovieIds </span><span style="color: gray">= </span><span style="color: red">'1,3,5'
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image66.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb65.png" width="413" height="147"></a></p>
<p>Now I have accomplished my goal to get rid of the dynamic sql to avoid security risks, and to be able to reuse cached execution plans.</p>
<p>There are a few corrections that need to be made to make this work for longer inputs. First of all we need to have more values in our numbers table. 1 to 5 only covers input string up to a length of 5. The where clause in the function can also be optimized a bit. I won’t go into the details, but the setup I often implement uses the code below:</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">Numbers </span><span style="color: gray">(
    </span><span style="color: teal">n </span><span style="color: blue">INT PRIMARY KEY
</span><span style="color: gray">)

</span><span style="color: green">--Fill data in Numbers table (this needs only to be done 1 time)
</span><span style="color: gray">;</span><span style="color: blue">WITH
  </span><span style="color: teal">Pass0 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">union </span><span style="color: gray">all </span><span style="color: blue">select </span>1<span style="color: gray">), </span><span style="color: green">--2 rows
  </span><span style="color: teal">Pass1 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">from </span><span style="color: teal">Pass0 </span><span style="color: blue">as </span><span style="color: teal">A</span><span style="color: gray">, </span><span style="color: teal">Pass0 </span><span style="color: blue">as </span><span style="color: teal">B</span><span style="color: gray">),</span><span style="color: green">--4 rows
  </span><span style="color: teal">Pass2 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">from </span><span style="color: teal">Pass1 </span><span style="color: blue">as </span><span style="color: teal">A</span><span style="color: gray">, </span><span style="color: teal">Pass1 </span><span style="color: blue">as </span><span style="color: teal">B</span><span style="color: gray">),</span><span style="color: green">--16 rows
  </span><span style="color: teal">Pass3 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">from </span><span style="color: teal">Pass2 </span><span style="color: blue">as </span><span style="color: teal">A</span><span style="color: gray">, </span><span style="color: teal">Pass2 </span><span style="color: blue">as </span><span style="color: teal">B</span><span style="color: gray">),</span><span style="color: green">--256 rows
  </span><span style="color: teal">Pass4 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">from </span><span style="color: teal">Pass3 </span><span style="color: blue">as </span><span style="color: teal">A</span><span style="color: gray">, </span><span style="color: teal">Pass3 </span><span style="color: blue">as </span><span style="color: teal">B</span><span style="color: gray">),</span><span style="color: green">--65.536 rows
  </span><span style="color: teal">Pass5 </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span>1 <span style="color: blue">as </span><span style="color: teal">C </span><span style="color: blue">from </span><span style="color: teal">Pass4 </span><span style="color: blue">as </span><span style="color: teal">A</span><span style="color: gray">, </span><span style="color: teal">Pass4 </span><span style="color: blue">as </span><span style="color: teal">B</span><span style="color: gray">),</span><span style="color: green">--4.294.967.296 rows
  </span><span style="color: teal">Tally </span><span style="color: blue">as </span><span style="color: gray">(</span><span style="color: blue">select </span><span style="color: magenta">row_number</span><span style="color: gray">() </span><span style="color: blue">over</span><span style="color: gray">(</span><span style="color: blue">order by </span><span style="color: teal">C</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">Number </span><span style="color: blue">from </span><span style="color: teal">Pass5</span><span style="color: gray">)
</span><span style="color: blue">INSERT </span><span style="color: teal">Numbers </span><span style="color: gray">(</span><span style="color: teal">n</span><span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: teal">Number
</span><span style="color: blue">FROM </span><span style="color: teal">Tally
</span><span style="color: blue">WHERE </span><span style="color: teal">Number </span><span style="color: gray">&lt; </span>1000000 <span style="color: green">--Fill 1 million rows (or as many as you like)
                       --This will fill approximately 13 MB
</span><span style="color: blue">GO

CREATE FUNCTION </span><span style="color: teal">[dbo]</span><span style="color: gray">.</span><span style="color: teal">[SplitToTable]
</span><span style="color: gray">(
    </span><span style="color: teal">@Input  </span><span style="color: blue">varchar</span><span style="color: gray">(</span>8000<span style="color: gray">),
    </span><span style="color: teal">@Delimiter </span><span style="color: blue">varchar</span><span style="color: gray">(</span>5<span style="color: gray">)
)
</span><span style="color: blue">RETURNS TABLE
AS

RETURN
</span><span style="color: gray">(
    </span><span style="color: blue">SELECT
        </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@Input</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: magenta">CHARINDEX</span><span style="color: gray">(</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">@Input</span><span style="color: gray">+</span><span style="color: teal">@Delimiter</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">) - </span><span style="color: teal">n</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">Val
    </span><span style="color: blue">FROM </span><span style="color: teal">Numbers
    </span><span style="color: blue">WHERE
        </span><span style="color: teal">n </span><span style="color: gray">&lt;= </span><span style="color: magenta">LEN</span><span style="color: gray">(</span><span style="color: teal">@Input</span><span style="color: gray">)
        AND </span><span style="color: magenta">SUBSTRING</span><span style="color: gray">(</span><span style="color: teal">@Delimiter </span><span style="color: gray">+ </span><span style="color: teal">@Input</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span>1<span style="color: gray">) = </span><span style="color: teal">@Delimiter
</span><span style="color: gray">)
</span><span style="color: blue">GO

SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">dbo</span><span style="color: gray">.</span><span style="color: teal">SplitToTable</span><span style="color: gray">(</span><span style="color: red">'hello|world|pipe|delimited|string'</span><span style="color: gray">, </span><span style="color: red">'|'</span><span style="color: gray">)
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image67.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb66.png" width="133" height="185"></a></p>
<p>&nbsp;</p>
<p>To use the Numbers table one needs to think a bit differently about things, than the normal way of solving problems. The way I described the solution in this blog post, pretty much covers how I often attach a new problem, where my gut tells me that the numbers table might come in handy. What if I need a table with all dates the next 30 days? Simple:</p>
<pre class="code"><span style="color: blue">SELECT </span><span style="color: magenta">DATEADD</span><span style="color: gray">(</span><span style="color: teal">DD</span><span style="color: gray">, </span><span style="color: teal">n</span><span style="color: gray">, </span><span style="color: red">'2012-04-01'</span><span style="color: gray">)
</span><span style="color: blue">FROM </span><span style="color: teal">Numbers
</span><span style="color: blue">WHERE </span><span style="color: teal">n </span><span style="color: gray">&lt;= </span>30
</pre>
<p>Sometimes I end up with pretty nifty solutions to crazy problems, that otherwise was really nasty to solve. This SplitToTable function is just one of the many examples of things to use the Numbers table for. If you would like to learn more about this, just google for auxiliary numbers table, and a lot of different solutions and ideas pop up.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/nifty-queries-using-a-numbers-helper-table/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Debugging query timeouts by sampling blocking &#8211; part 2</title>
		<link>http://www.geniiius.com/blog/debugging-query-timeouts-by-sampling-blocking-part-2/</link>
		<comments>http://www.geniiius.com/blog/debugging-query-timeouts-by-sampling-blocking-part-2/#comments</comments>
		<pubDate>Thu, 15 Mar 2012 15:30:46 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Performance optimization]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=954</guid>
		<description><![CDATA[In part 1 I explained how I was hunting for the root cause for some query timeouts that happened every once in a while. I knew for certain, that the affected queries were waiting for 30 seconds for an intent exclusive lock on something, before a timeout occurs. Our good old friend sys.sysprocesses actually gives...]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.geniiius.com/blog/debugging-query-timeouts-with-x-events-part-1/">part 1</a> I explained how I was hunting for the root cause for some query timeouts that happened every once in a while. I knew for certain, that the affected queries were waiting for 30 seconds for an intent exclusive lock on something, before a timeout occurs.</p>
<p>Our good old friend sys.sysprocesses actually gives us this kind of information. Let me use the same setup as I did in part 1 to trigger a blocking scenario. From connection 1 I’m execution the following, which leaves an open transaction that holds a lock on the DummyTable:</p>
<p>&nbsp;</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">DummyTable </span><span style="color: gray">(</span><span style="color: teal">col1 </span><span style="color: blue">INT</span><span style="color: gray">)
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">DummyTable </span><span style="color: gray">(</span><span style="color: teal">col1</span><span style="color: gray">) </span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">)
</span><span style="color: blue">GO

BEGIN TRAN
GO
DELETE FROM </span><span style="color: teal">DummyTable
</span><span style="color: blue">WAITFOR DELAY </span><span style="color: red">'00:01:00'
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>From connection 2 I’m executing the following, which will keep running until connection 1 either performs a commit or a rollback:</p>
<pre class="code"><span style="color: blue">DELETE FROM </span><span style="color: teal">DummyTable
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>From a third connection I’m running this query agains sys.sysprocesses:</p>
<pre class="code"><span style="color: blue">SELECT
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">spid</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">blocked </span><span style="color: blue">as </span><span style="color: teal">BlockingSPID</span><span style="color: gray">,
    </span><span style="color: magenta">DB_NAME</span><span style="color: gray">(</span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: blue">dbid</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">DatabaseName</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: magenta">program_name</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">loginame</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">waitresource</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">lastwaittype
</span><span style="color: blue">FROM </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">sysprocesses </span><span style="color: teal">procs
</span><span style="color: blue">WHERE </span><span style="color: teal">spid </span><span style="color: gray">IN (</span>54<span style="color: gray">,</span>55<span style="color: gray">)
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image58.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb57.png" width="688" height="67"></a></p>
<p>SPID = 54 is my connection 1, and SPID = 55 is my second connection.</p>
<p>The output shows that that my connection 2 (spid 55) is blocked by spid = 54, while waiting to acquire a LCK_M_U on the resource RID:6:1:169:0. This is pretty usefull information, if we could just get the sql text returned as well. And luckily we can <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile13.png"></p>
<p>We can extend the query to OUTER APPLY sys.dm_exec_sql_text. This will give us the text of the queries, so lets see how that goes:</p>
<p>&nbsp;</p>
<pre class="code"><span style="color: blue">SELECT
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">spid</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">blocked </span><span style="color: blue">as </span><span style="color: teal">BlockingSPID</span><span style="color: gray">,
    </span><span style="color: magenta">DB_NAME</span><span style="color: gray">(</span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: blue">dbid</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">DatabaseName</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: magenta">program_name</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">loginame</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">waitresource</span><span style="color: gray">,
    </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">lastwaittype</span><span style="color: gray">,
    </span><span style="color: blue">text
FROM </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">sysprocesses </span><span style="color: teal">procs
</span><span style="color: gray">OUTER APPLY </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_sql_text</span><span style="color: gray">(</span><span style="color: blue">sql_handle</span><span style="color: gray">)
</span><span style="color: blue">WHERE </span><span style="color: teal">spid </span><span style="color: gray">IN (</span>54<span style="color: gray">,</span>55<span style="color: gray">)
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image59.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb58.png" width="833" height="59"></a></p>
<p>Now we are actually able to see the exact query that is causing the blocking. <br />Because I knew that the blocking was going on for at least 30 seconds, I simply needed to sample this data every 15. seconds, untill I had cought my sinner. I simply create a temporary table to hold the data, and the created a loop that would run until I stopped it manually. By creating a recursive query, I could also find the blocking chain – so the final query looked like this:</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">#Blocking
</span><span style="color: gray">(
    </span><span style="color: blue">Timestamp DATETIME</span><span style="color: gray">,
    </span><span style="color: teal">SPID </span><span style="color: blue">SMALLINT</span><span style="color: gray">,
    </span><span style="color: teal">BlockingSPID </span><span style="color: blue">INT</span><span style="color: gray">,
    </span><span style="color: teal">DatabaseName </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>255<span style="color: gray">),
    </span><span style="color: teal">LoginName </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>255<span style="color: gray">),
    </span><span style="color: teal">ProgramName </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>255<span style="color: gray">),
    </span><span style="color: teal">BlockingStatement </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span><span style="color: magenta">MAX</span><span style="color: gray">),
    </span><span style="color: teal">Waitresource </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>500<span style="color: gray">),
    </span><span style="color: teal">lastwaittype </span><span style="color: blue">VARCHAR</span><span style="color: gray">(</span>500<span style="color: gray">),
    </span><span style="color: teal">RowNo </span><span style="color: blue">BIGINT</span><span style="color: gray">,
    </span><span style="color: teal">LevelRow </span><span style="color: blue">INT
</span><span style="color: gray">)

</span><span style="color: green">--Run until manually stopped
</span><span style="color: blue">WHILE </span><span style="color: gray">(</span>1<span style="color: gray">=</span>1<span style="color: gray">)
</span><span style="color: blue">BEGIN
    </span><span style="color: gray">;</span><span style="color: blue">WITH </span><span style="color: teal">Processes
    </span><span style="color: blue">AS
    </span><span style="color: gray">(
    </span><span style="color: blue">SELECT
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">spid</span><span style="color: gray">,
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">blocked </span><span style="color: blue">AS </span><span style="color: teal">BlockingSPID</span><span style="color: gray">,
        </span><span style="color: magenta">DB_NAME</span><span style="color: gray">(</span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: blue">dbid</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">DatabaseName</span><span style="color: gray">,
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: magenta">program_name </span><span style="color: blue">AS </span><span style="color: teal">ProgramName</span><span style="color: gray">,
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">loginame </span><span style="color: blue">AS </span><span style="color: teal">LoginName</span><span style="color: gray">,
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">waitresource</span><span style="color: gray">,
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">lastwaittype</span><span style="color: gray">,
        </span><span style="color: magenta">CAST</span><span style="color: gray">(</span><span style="color: blue">text AS VARCHAR</span><span style="color: gray">(</span><span style="color: magenta">MAX</span><span style="color: gray">)) </span><span style="color: blue">AS Text
    FROM
        </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">sysprocesses </span><span style="color: teal">procs
        </span><span style="color: gray">CROSS APPLY </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: green">dm_exec_sql_text </span><span style="color: gray">(</span><span style="color: blue">sql_handle</span><span style="color: gray">)
    </span><span style="color: blue">WHERE
        </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">spid </span><span style="color: gray">&gt; </span>50
    <span style="color: gray">), </span><span style="color: teal">Blocking
    </span><span style="color: blue">AS
     </span><span style="color: gray">(
        </span><span style="color: green">--Define base of recursive query
        </span><span style="color: blue">SELECT
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">SPID</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">DatabaseName</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">LoginName</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">ProgramName</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: blue">Text</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">Waitresource</span><span style="color: gray">,
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">lastwaittype</span><span style="color: gray">,
            </span><span style="color: magenta">ROW_NUMBER</span><span style="color: gray">() </span><span style="color: blue">OVER</span><span style="color: gray">(</span><span style="color: blue">ORDER BY </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">SPID</span><span style="color: gray">) </span><span style="color: blue">as </span><span style="color: teal">RowNo</span><span style="color: gray">,
            </span>0 <span style="color: blue">AS </span><span style="color: teal">LevelRow
        </span><span style="color: blue">FROM
            </span><span style="color: teal">Processes procs
            </span><span style="color: gray">JOIN </span><span style="color: teal">Processes procs2 </span><span style="color: blue">ON </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">SPID </span><span style="color: gray">= </span><span style="color: teal">procs2</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID
        </span><span style="color: blue">WHERE
            </span><span style="color: teal">procs</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID </span><span style="color: gray">= </span>0
        <span style="color: blue">UNION </span><span style="color: gray">ALL
        </span><span style="color: green">--UNION the recursive step
        </span><span style="color: blue">SELECT
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">SPID</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">DatabaseName</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">LoginName</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">ProgramName</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: blue">Text</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">Waitresource</span><span style="color: gray">,
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">lastwaittype</span><span style="color: gray">,
            </span><span style="color: teal">d</span><span style="color: gray">.</span><span style="color: teal">RowNo</span><span style="color: gray">,
            </span><span style="color: teal">d</span><span style="color: gray">.</span><span style="color: teal">LevelRow </span><span style="color: gray">+ </span>1
        <span style="color: blue">FROM
            </span><span style="color: teal">Processes ProcsR
            </span><span style="color: gray">JOIN </span><span style="color: teal">Blocking d </span><span style="color: blue">ON </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID </span><span style="color: gray">= </span><span style="color: teal">d</span><span style="color: gray">.</span><span style="color: teal">SPID
         </span><span style="color: blue">WHERE
            </span><span style="color: teal">ProcsR</span><span style="color: gray">.</span><span style="color: teal">BlockingSPID </span><span style="color: gray">&gt; </span>0
    <span style="color: gray">)
    </span><span style="color: blue">INSERT INTO </span><span style="color: teal">#Blocking
    </span><span style="color: blue">SELECT </span><span style="color: magenta">GETDATE</span><span style="color: gray">() </span><span style="color: blue">as Timestamp</span><span style="color: gray">, * </span><span style="color: blue">FROM </span><span style="color: teal">Blocking

    </span><span style="color: green">--Wait for 15 seconds before starting over
    </span><span style="color: blue">WAITFOR DELAY </span><span style="color: red">'00:00:15'
</span><span style="color: blue">END
</span></pre>
<p>&nbsp;</p>
<p>This query is using multiple leves of CTE’s, with the first level named Processes beeing pretty much identical to the query showed before. The next level CTE called Blocking is used to create the recursive structure making it possible to identify the blocking chain. My connection 1 and 2 were still running, so running the above query for just a few seconds, samples the data I want:</p>
<pre class="code"><span style="color: green">--After stopping the sampling manually:
</span><span style="color: blue">SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">#Blocking
</span><span style="color: blue">ORDER BY Timestamp</span><span style="color: gray">, </span><span style="color: teal">RowNo</span><span style="color: gray">, </span><span style="color: teal">LevelRow
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image60.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb59.png" width="1322" height="103"></a></p>
<p>Each sample will have the same values in the Timestamp column. For each sampling each blocking chain will have the same value in RowNo, and LevelRow orders the statements in the blocking chain. <br />In my example, I only ran the sampling query long enough to get one sample. And the only blocking happening on the system was my two connections, so only one blocking chain was captured… the one with RowNo = 1. <br />LevelRow = 0 is the root of the blocking chain, and in my example this is my connection 1.</p>
<p>So by running the above query on the production system, and yet again waiting for the timeouts to occur, I was actually able to identify the root cause for all the timeouts I was debugging. The blocking query was holding a table lock for a long time, which perfectly explained what was happening. Fixing the root cause is another story, which is not in scope of this post.</p>
<h3>Wrap up</h3>
<p>A system was experiencing intermittent query timeouts. My debugging process was:</p>
<ol>
<li>Use a classic server side trace to catch the queries that timed out, to figure out if they were using up resources for more than 30 seconds, or if they were waiting for something.</li>
<li>It turned out they were waiting for something, so I ran a XEvent session to track all wait events with a duration &gt; 200 ms (<a href="http://www.geniiius.com/blog/debugging-query-timeouts-with-x-events-part-1/">part 1 of this blog post series</a>)</li>
<li>The XEvent session revealed that the queries were waiting to acquire an intent exclusive lock, so the next step was to sample blocking chains to find the root query (This blog post)</li>
<li>The blocking sampling revealed the query that caused heavy table locks, and now it was easy to go ahead and fixing the problem.</li>
</ol>
<h3>But remember..</h3>
<p>The debugging process will not work for hunting down the root cause for all scenarios. The outcome of each step determines what the next step should be. So if my initial server side trace had shown heavy cpu usage for the entire 30 seconds, then my next step would be to look into execution plans etc. So in that case it wouldn’t make sense to use the XEvent sessions to capture wait_info and continue down that path. <br />Nevertheless I hope this little blog post series gave you an idea how you could hunt down your own nasty queries <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile13.png"></p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/debugging-query-timeouts-by-sampling-blocking-part-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Debugging query timeouts with X-Events &#8211; part 1</title>
		<link>http://www.geniiius.com/blog/debugging-query-timeouts-with-x-events-part-1/</link>
		<comments>http://www.geniiius.com/blog/debugging-query-timeouts-with-x-events-part-1/#comments</comments>
		<pubDate>Sat, 10 Mar 2012 11:59:51 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Performance optimization]]></category>
		<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[XEvents]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=946</guid>
		<description><![CDATA[I like hunting. Not the kind where you are walking around the forrest and trying to find a target. No, I like hunting for SQL queries that are messy, or down right nasty. My latest hunting adventure was to find the root cause for intermittent query timeouts, that could happen sometimes 3 times per day,...]]></description>
			<content:encoded><![CDATA[<p>I like hunting. Not the kind where you are walking around the forrest and trying to find a target. No, I like hunting for SQL queries that are messy, or down right nasty. My latest hunting adventure was to find the root cause for intermittent query timeouts, that could happen sometimes 3 times per day, and sometimes not for days. My starting point was, that I knew from the application, that it was a command timeout that occured, and the timeout value was 30 seconds.</p>
<p>So I knew that the queries did not complete in 30 seconds, but I also knew that the queries were executed thousands of times during a day, with no problem at all.</p>
<p>I didn’t know if the queries were actually hitting the cpu/disks heavily, or if they were blocked by something. If they were waiting for something, I didn’t know if it was physical resources like disk, cpu, network or if it was a lock on an object. If they were hitting the physical resources, it might be a bad execution plan, messed up statistics or a sick index that was the cause.</p>
<p>To answer some of the unknowns, I started a basic sql server trace, and caught all queries with a duration &gt; 25 seconds. After running that trace a couple of days, the timeouts finally happened again. From the trace I could see that the queries had a duration of ~30.000 ms, but a cpu value of only 1-200 ms. The number of reads were also close to zero. This meant, that a bad execution plan wasn’t the cause, but some waiting/blocking was going on. I just couldn’t see what it was from the sql server trace.</p>
<p><strong>X-Events to the rescue!</strong></p>
<p>X-Event Sessions is the new tracing method introduced with SQL Server 2008, which is more lightweight than a classic profiling/tracing, and it is also able to give more detailed information. I won’t go into the details of XEvents in this blog post, but just show you how I used it for this specific task.</p>
<h3>The goal</h3>
<p>The goal for this X-Event tracing was to be able to find out what the queries were waiting for. It could either be other queries that had a lock on objects, or it could be a lack of physical resources in the server.</p>
<h3>The code</h3>
<p>To create the X-Event session, you simply need to run this:</p>
<pre class="code"><span style="color: blue">CREATE EVENT SESSION </span><span style="color: teal">[WaitEvents] </span><span style="color: blue">ON SERVER
ADD EVENT </span><span style="color: teal">sqlos</span><span style="color: gray">.</span><span style="color: teal">wait_info
</span><span style="color: gray">(
    </span><span style="color: blue">ACTION</span><span style="color: gray">(
        </span><span style="color: teal">sqlserver</span><span style="color: gray">.</span><span style="color: teal">database_id</span><span style="color: gray">,
        </span><span style="color: teal">sqlserver</span><span style="color: gray">.</span><span style="color: teal">session_id</span><span style="color: gray">,
        </span><span style="color: teal">sqlserver</span><span style="color: gray">.</span><span style="color: teal">sql_text</span><span style="color: gray">,
        </span><span style="color: teal">sqlserver</span><span style="color: gray">.</span><span style="color: teal">plan_handle
        </span><span style="color: gray">)
    </span><span style="color: blue">WHERE
        </span><span style="color: teal">opcode </span><span style="color: gray">= </span>1 <span style="color: gray">AND </span><span style="color: teal">duration </span><span style="color: gray">&gt; <font color="#000000">200 <span style="color: gray">AND </span><span style="color: teal">session_id </span><span style="color: gray">&gt; 50</span></font></span>
<span style="color: gray">)
</span><span style="color: blue">ADD TARGET </span><span style="color: teal">package0</span><span style="color: gray">.</span><span style="color: teal">asynchronous_file_target
    </span><span style="color: gray">(</span><span style="color: blue">SET FILENAME </span><span style="color: gray">= </span><span style="color: red">N'C:\XEvents\WaitEvents.xel'</span><span style="color: gray">,
    </span><span style="color: teal">METADATAFILE </span><span style="color: gray">= </span><span style="color: red">N'C:\XEvents\WaitEvents.xem'</span><span style="color: gray">)
</span><span style="color: blue">WITH </span><span style="color: gray">(</span><span style="color: teal">EVENT_RETENTION_MODE</span><span style="color: gray">=</span><span style="color: teal">ALLOW_SINGLE_EVENT_LOSS</span><span style="color: gray">,
    </span><span style="color: teal">MAX_DISPATCH_LATENCY</span><span style="color: gray">=</span>5 <span style="color: teal">SECONDS</span><span style="color: gray">)
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>Just adjust the path to the files to match your server.<br />The session triggers on events of the type sqlos.wait_info. This triggers an event on every wait event that is happening on the system.<br />The ACTION part defines the information I want extracted. In this case I just want the database_id, session_id, sql_text as well as the plan_handle to be able to see the actual execution plan for that specific query at that specific time.<br />The opcode=1 filters out so we only get the “end” events.<br />session_id &gt; 50 ensures that we only get events caused by user sessions. If the root cause happens to be some SQL Server internal stuff, then we might miss it – but my gut feeling told me that it was ok in this case.<br />duration &gt; 200 ensures that we are not getting spammed with a lot af small wait events for all io operations. If the root cause is a lot of slow IO’s, then&nbsp; it might not be caught by this XEvent session. If that’s the case, it’s just a matter of adjusting the values. The lower value, the more events you will collect.</p>
<p>Because I need to have this X-Event session running for a couple of days, I want to store the events in files, so the ADD TARGET simply does that. </p>
<p>The session isn’t running per default, so we need to start it manually:</p>
<pre class="code"><span style="color: blue">ALTER EVENT SESSION </span><span style="color: teal">[WaitEvents] </span><span style="color: blue">ON SERVER
STATE </span><span style="color: gray">= </span><span style="color: teal">START
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>Stopping the session is as simple as:</p>
<pre class="code"><span style="color: blue">ALTER EVENT SESSION </span><span style="color: teal">[WaitEvents] </span><span style="color: blue">ON SERVER
STATE </span><span style="color: gray">= </span><span style="color: teal">STOP
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>And dropping it entirely from the server:</p>
<pre class="code"><span style="color: blue">DROP EVENT SESSION </span><span style="color: teal">[WaitEvents] </span><span style="color: blue">ON SERVER
</span></pre>
<p>&nbsp;</p>
<p>Like a server side trace, we are able to leave the session definition on the server, and then just starting and stopping it when we need to collect data.</p>
<p><strong>Generating dummy events</strong></p>
<p>While the above XEvent session was running on my test setup, I ran the following from connection 1:</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">DummyTable </span><span style="color: gray">(</span><span style="color: teal">col1 </span><span style="color: blue">INT</span><span style="color: gray">)
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">DummyTable </span><span style="color: gray">(</span><span style="color: teal">col1</span><span style="color: gray">) </span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">)
</span><span style="color: blue">GO

WAITFOR DELAY </span><span style="color: red">'00:00:01'
</span><span style="color: blue">GO

BEGIN TRAN
GO
DELETE FROM </span><span style="color: teal">DummyTable
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>This leaves an open transaction which holds a lock on the DummyTable. From connection 2 I then ran this:</p>
<p>&nbsp;</p>
<pre class="code"><span style="color: blue">DELETE FROM </span><span style="color: teal">DummyTable
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>I then aborted the query from connection 2, and committed the transaction from connection 1. I then stopped the X-Event session with the STOP command above, and was ready to analyze the data.</p>
<p><strong>Analyzing the data</strong></p>
<p>To analyze the data we need to do some XQuery magic. To be honest, I’m not too comfortable writing these queries from scratch, but luckily it’s easy to find tons of examples on the internet. If you haven’t found a query that matches your XEvent session 100%, then it’s most often easy to adjust the scripts to do so.</p>
<p>The query I ended up with, was this (Don’t worry, it’s not as nasty as it might seem <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile12.png">)</p>
<pre class="code"><span style="color: gray">;</span><span style="color: blue">WITH </span><span style="color: teal">MyXEventData </span><span style="color: blue">AS </span><span style="color: gray">(
</span><span style="color: blue">SELECT
</span><span style="color: magenta">DATEADD</span><span style="color: gray">(</span><span style="color: teal">hh</span><span style="color: gray">,
</span><span style="color: magenta">DATEDIFF</span><span style="color: gray">(</span><span style="color: teal">hh</span><span style="color: gray">, </span><span style="color: magenta">GETUTCDATE</span><span style="color: gray">(), </span><span style="color: magenta">CURRENT_TIMESTAMP</span><span style="color: gray">),
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/@timestamp)[1]'</span><span style="color: gray">, </span><span style="color: red">'datetime2'</span><span style="color: gray">)) </span><span style="color: blue">AS </span><span style="color: teal">[timestamp]</span><span style="color: gray">,
</span><span style="color: magenta">COALESCE</span><span style="color: gray">(</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/data[@name="database_id"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'int'</span><span style="color: gray">),
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/action[@name="database_id"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'int'</span><span style="color: gray">)) </span><span style="color: blue">AS </span><span style="color: teal">database_id</span><span style="color: gray">,
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/action[@name="session_id"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'int'</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">[session_id]</span><span style="color: gray">,
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/data[@name="wait_type"]/text)[1]'</span><span style="color: gray">, </span><span style="color: red">'nvarchar(4000)'</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">[wait_type]</span><span style="color: gray">,
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/data[@name="duration"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'bigint'</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">[duration]</span><span style="color: gray">,
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/action[@name="plan_handle"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'nvarchar(4000)'</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">[plan_handle]</span><span style="color: gray">,
</span><span style="color: teal">XEventData</span><span style="color: gray">.</span><span style="color: teal">value</span><span style="color: gray">(</span><span style="color: red">'(event/action[@name="sql_text"]/value)[1]'</span><span style="color: gray">, </span><span style="color: red">'nvarchar(4000)'</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">[sql_text]
</span><span style="color: blue">FROM </span><span style="color: gray">(
    </span><span style="color: blue">SELECT </span><span style="color: magenta">CAST </span><span style="color: gray">(</span><span style="color: teal">event_data </span><span style="color: blue">AS XML</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">XEventData
    </span><span style="color: blue">FROM </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_xe_file_target_read_file </span><span style="color: gray">(
        </span><span style="color: red">'C:\XEvents\WaitEvents*.xel'</span><span style="color: gray">,
        </span><span style="color: red">'C:\XEvents\WaitEvents*.xem'</span><span style="color: gray">, null, null)) </span><span style="color: teal">RawData
</span><span style="color: gray">)
</span><span style="color: blue">SELECT </span><span style="color: gray">*
</span><span style="color: blue">FROM </span><span style="color: teal">MyXEventData
</span></pre>
<p>&nbsp;</p>
<p>The query uses a CTE (Common Table Expression) to wrap the nasty xml stuff, and making it way easier to write simple queries against the CTE in the end.<br />Let’s break this down a bit. The following part simply reads the content of the files, and returns the entire xml as a column called XEventData:</p>
<p><span style="color: blue">SELECT </span><span style="color: magenta">CAST </span><span style="color: gray">(</span><span style="color: teal">event_data </span><span style="color: blue">AS XML</span><span style="color: gray">) </span><span style="color: blue">AS </span><span style="color: teal">XEventData<br /></span><span style="color: blue">FROM </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_xe_file_target_read_file </span><span style="color: gray">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: red">&#8216;C:\XEvents\WaitEvents*.xel&#8217;</span><span style="color: gray">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: red">&#8216;C:\XEvents\WaitEvents*.xem&#8217;</span><span style="color: gray">, null, null)) </span><span style="color: teal">RawData<br /></span></p>
<p>This sub-select is what we execute the XQuery expressions against, to fetch the relevant data from within the xml document. Since this is not a blog post about XML and XQuerying, let’s just skip the details, and go to the resulting output from the entire query:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image57.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb56.png" width="678" height="97"></a></p>
<p>The first event was my WAITFOR DELAY query, which by design was waiting for 1 second. The wait_type is WAITFOR. The duration column says 1001 ms, which is pretty close to the expected 1 sec. </p>
<p>The second event was our DELETE statement from connection 2. This was waiting for 2166 ms before I manually aborted the query. The wait_type was LCK_M_U.</p>
<p><strong>Back to my hunting experience</strong></p>
<p>Using the XEvent session as demonstrated above, I ran it on the production system to find out what the timed out queries were waiting for. After a bunch of timeouts had happened, I found all the matching wait events, and they all had a matching wait event of type LCK_M_IX with a duration of ~30000 ms. The LCK_M_IX is an intent exclusive lock, which confirms my gut feeling.</p>
<p>Know I knew for certain, that some other query was blocking for a long time period. And since the affected queries were both inserts, updates and deletes, I thought I was dealing with a table lock. But I didn’t know for sure, and I didn’t know which query was the sinner.</p>
<p><strong>Next step</strong></p>
<p>The next is to identify the query that caused the blocking. I will show you how to do that in part 2 of this blog post, so keep and eye out for it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/debugging-query-timeouts-with-x-events-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to use Change Data Capture (CDC)</title>
		<link>http://www.geniiius.com/blog/how-to-use-change-data-capture-cdc/</link>
		<comments>http://www.geniiius.com/blog/how-to-use-change-data-capture-cdc/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 19:11:04 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Script toolbox]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[CDC]]></category>
		<category><![CDATA[Change Data Capture]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[T-SQL]]></category>

		<guid isPermaLink="false">http://www.geniiius.com/?p=939</guid>
		<description><![CDATA[With SQL Server 2008 Microsoft added the CDC feature to SQL Server enterprise edition. I haven’t come to play around with it before, but the other day I was asked if CDC might be used for a specific purpose. Because I had no previous experience using CDC, I had to check it out. The Quest...]]></description>
			<content:encoded><![CDATA[<p>With SQL Server 2008 Microsoft added the CDC feature to SQL Server enterprise edition. I haven’t come to play around with it before, but the other day I was asked if CDC might be used for a specific purpose. Because I had no previous experience using CDC, I had to check it out.</p>
<h3>The Quest</h3>
<p>The Quest was to be able to provide a system with undo/redo capabilities, so if a user had entered (and committed) incorrect data, it should be possible to rollback to any given time before that happened. Backup/restore wasn’t an option, because only a specific subset of data should be rolled back (let’s say a specific UserId)</p>
<h3>The idea</h3>
<p>The idea was to either build a tracking system manually using triggers, or to look into the CDC possibilities. The idea I will try out with this small demo, is to use CDC to read the data from a previous point in time, and then use the MERGE statement to revert the data.</p>
<h3>The solution</h3>
<p>First I’ll create a database and enable CDC:</p>
<pre class="code"><span style="color: blue">USE master
go
CREATE DATABASE </span><span style="color: teal">TestCDC
</span><span style="color: blue">GO
USE </span><span style="color: teal">TestCDC
</span><span style="color: blue">GO
EXEC </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: maroon">sp_cdc_enable_db
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>Next I will create a table “Timelog”, and enable CDC on it. The Timelog table is the one we want the undo/redo capabillity on.</p>
<pre class="code"><span style="color: blue">CREATE TABLE </span><span style="color: teal">TimeLog </span><span style="color: gray">(
    </span><span style="color: teal">TimeLogId </span><span style="color: blue">INT IDENTITY PRIMARY KEY</span><span style="color: gray">,
    </span><span style="color: teal">UserId </span><span style="color: blue">INT </span><span style="color: gray">NOT NULL,
    </span><span style="color: teal">TimeStart </span><span style="color: blue">DATETIME </span><span style="color: gray">NOT NULL,
    </span><span style="color: teal">TimeEnd </span><span style="color: blue">DATETIME </span><span style="color: gray">NULL,
    </span><span style="color: blue">Description VARCHAR</span><span style="color: gray">(</span>200<span style="color: gray">),
    </span><span style="color: teal">Created </span><span style="color: blue">DATETIME DEFAULT </span><span style="color: magenta">GETDATE</span><span style="color: gray">(),
    </span><span style="color: teal">Modified </span><span style="color: blue">DATETIME DEFAULT </span><span style="color: magenta">GETDATE</span><span style="color: gray">()
)
</span><span style="color: blue">GO

EXEC </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: maroon">sp_cdc_enable_table
</span><span style="color: teal">@source_schema </span><span style="color: gray">= </span><span style="color: red">N'dbo'</span><span style="color: gray">,
</span><span style="color: teal">@source_name   </span><span style="color: gray">= </span><span style="color: red">N'TimeLog'</span><span style="color: gray">,
</span><span style="color: teal">@role_name     </span><span style="color: gray">= NULL,
</span><span style="color: teal">@filegroup_name </span><span style="color: gray">= </span><span style="color: red">N'PRIMARY'</span><span style="color: gray">,
</span><span style="color: teal">@supports_net_changes </span><span style="color: gray">= </span>1
<span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>The <a href="http://msdn.microsoft.com/en-us/library/bb522475.aspx">sys.sp_cdc_enable_table</a> procedure gives the possibilities to control which filegroup the change data should be stored on, as well as a role to control access to the data. For this demo I’ll just store the data in the PRIMARY filegroup. CDC relies on SQL Server Agent to be running, so make sure it is so before running the sys.sp_cdc_enable_table procedure.</p>
<p>Next up is inserting some data to simulate one user performing a few correct time registrations, and another user registering some wrong data. I have put in a WAITFOR DELAY, which simulates that some time has past on since the last registration. It does not matter if it is seconds or months.</p>
<pre class="code"><span style="color: green">/*
Two users - userid 1 and 2
User 1 makes 3 registrations, but the third (the update) is wrong
User 2 makes 2 registrations, both are correct.
User 1 makes 1 correct registration</span></pre>
<pre class="code"><span style="color: green">*/
--Correct registration
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">TimeLog </span><span style="color: gray">(</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">, </span><span style="color: red">'2012-01-01 10:00:00'</span><span style="color: gray">, </span><span style="color: red">'1st work day'</span><span style="color: gray">)
</span><span style="color: blue">GO
WAITFOR DELAY </span><span style="color: red">'00:00:02'

</span><span style="color: green">--Correct registration
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">TimeLog </span><span style="color: gray">(</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">, </span><span style="color: red">'2012-01-02 10:00:00'</span><span style="color: gray">, </span><span style="color: red">'2nd work day'</span><span style="color: gray">)
</span><span style="color: blue">GO
WAITFOR DELAY </span><span style="color: red">'00:00:02'

</span><span style="color: green">--Wrong registration/update
</span><span style="color: magenta">UPDATE </span><span style="color: teal">TimeLog
</span><span style="color: blue">SET
    </span><span style="color: teal">TimeEnd </span><span style="color: gray">= </span><span style="color: red">'2013-01-01 19:00:00'</span><span style="color: gray">,
    </span><span style="color: teal">Modified </span><span style="color: gray">= </span><span style="color: magenta">GETDATE</span><span style="color: gray">()
</span><span style="color: blue">WHERE
    </span><span style="color: teal">UserId </span><span style="color: gray">= </span>1
    <span style="color: gray">AND </span><span style="color: teal">TimeStart </span><span style="color: gray">= </span><span style="color: red">'2012-01-01 10:00:00'
</span><span style="color: blue">GO
WAITFOR DELAY </span><span style="color: red">'00:00:02'

</span><span style="color: green">--Correct registration
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">TimeLog </span><span style="color: gray">(</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>2<span style="color: gray">, </span><span style="color: red">'2012-01-01 09:00:00'</span><span style="color: gray">, </span><span style="color: red">'1st work day'</span><span style="color: gray">)
</span><span style="color: blue">GO
WAITFOR DELAY </span><span style="color: red">'00:00:02'

</span><span style="color: green">--Correct registration
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">TimeLog </span><span style="color: gray">(</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>2<span style="color: gray">, </span><span style="color: red">'2012-01-02 09:00:00'</span><span style="color: gray">, </span><span style="color: red">'2nd work day'</span><span style="color: gray">)
</span><span style="color: blue">GO
WAITFOR DELAY </span><span style="color: red">'00:00:02'

</span><span style="color: green">--Correct registration
</span><span style="color: blue">INSERT INTO </span><span style="color: teal">TimeLog </span><span style="color: gray">(</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">)
</span><span style="color: blue">VALUES </span><span style="color: gray">(</span>1<span style="color: gray">, </span><span style="color: red">'2012-01-03 10:00:00'</span><span style="color: gray">, </span><span style="color: red">'3rd work day'</span><span style="color: gray">)
</span><span style="color: blue">GO
</span></pre>
<p>&nbsp;</p>
<p>Let’s see how the data looks now:</p>
<pre class="code"><span style="color: green">--Notice TimeLogId = 1.
--The TimeEnd shouldn't be in 2013.
</span><span style="color: blue">SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">TimeLog

</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image52.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb51.png" width="568" height="159"></a></p>
<p>CDC adds a few functions that we can use to select the changes that has happened. The first we will use, is <a href="http://msdn.microsoft.com/en-us/library/bb500137.aspx">sys.fn_cdc_map_time_to_lsn</a>, which takes a datetime as input, and returns the lsn (Transaction log sequence number) that matches the timestamp. It is also fed with a string value that tells if it should return the lsn that is </p>
<ul>
<li>largest less than</li>
<li>largest less than or equal</li>
<li>smallest greater than</li>
<li>smallest greater than or equal</li>
</ul>
<p>I’m interested in all changes that has happened on the table within the last 24 hours, so I’ll use the following lines to find those lsn’s:</p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@begin_time </span><span style="color: blue">datetime</span><span style="color: gray">, </span><span style="color: teal">@end_time </span><span style="color: blue">datetime</span><span style="color: gray">, </span><span style="color: teal">@begin_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">), </span><span style="color: teal">@end_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">);
</span><span style="color: blue">SET </span><span style="color: teal">@begin_time </span><span style="color: gray">= </span><span style="color: magenta">GETDATE</span><span style="color: gray">()-</span>1
<span style="color: blue">SET </span><span style="color: teal">@end_time </span><span style="color: gray">= </span><span style="color: magenta">GETDATE</span><span style="color: gray">()
</span><span style="color: blue">SELECT </span><span style="color: teal">@begin_lsn </span><span style="color: gray">= </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'smallest greater than'</span><span style="color: gray">, </span><span style="color: teal">@begin_time</span><span style="color: gray">);
</span><span style="color: blue">SELECT </span><span style="color: teal">@end_lsn </span><span style="color: gray">= </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'largest less than or equal'</span><span style="color: gray">, </span><span style="color: teal">@end_time</span><span style="color: gray">);
</span></pre>
<p>&nbsp;</p>
<p>Now I have the lsn of the smallest lsn that has happened after the point in time GETDATE()-1 which is 24 hours ago. I also have the lsn of the last lsn that has happened before (or equal to) GETDATE(). This leads me to the next functions available. After enabling CDC on the table, a few functions and system tables was automatically added to my database:</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image53.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb52.png" width="418" height="486"></a></p>
<p>&nbsp;</p>
<p> The next function I’ll use, is the one called <a href="http://msdn.microsoft.com/en-us/library/bb510627.aspx">cdc.fn_cdc_get_all_changes_dbo_TimeLog</a>. It’s called with the two lsn’s found above like this:</p>
<pre class="code"><span style="color: blue">SELECT </span><span style="color: gray">*
</span><span style="color: blue">FROM </span><span style="color: teal">cdc</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_get_all_changes_dbo_TimeLog</span><span style="color: gray">(</span><span style="color: teal">@begin_lsn</span><span style="color: gray">, </span><span style="color: teal">@end_lsn</span><span style="color: gray">, </span><span style="color: red">'all update old'</span><span style="color: gray">)
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image54.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb53.png" width="637" height="96"></a></p>
<p>I now get all the changes that has happened, and updates will be listed as a trigger solution would, by having both a delete and insert row to hold the data from before the update and after. </p>
<p>Now UserId = 1 realizes that invalid registrations have found its way in the table. If we look at the CDC data, then UserId = 1 created an error at the transaction with lsn = 0x0000002C0000013B0003 which happened at ‘2012-03-05 19:38:04.727’. Another function can now be used to find the netto change up until right before that time. And because we started the cdc on an empty table, the netto change correspond to how the table looked at that time. The function is similar to the <a href="http://msdn.microsoft.com/en-us/library/bb510627.aspx">cdc.fn_cdc_get_all_changes_dbo_TimeLog()</a> we used before, now it’s just called <a href="http://msdn.microsoft.com/en-us/library/bb522511.aspx">_net_</a> instead of _all_. So let’s try it out:</p>
<pre class="code"><span style="color: blue">DECLARE </span><span style="color: teal">@begin_time </span><span style="color: blue">datetime </span><span style="color: gray">= </span><span style="color: magenta">GETDATE</span><span style="color: gray">()-</span>1
<span style="color: blue">DECLARE </span><span style="color: teal">@end_time </span><span style="color: blue">datetime </span><span style="color: gray">= </span><span style="color: red">'2012-03-05 19:38:04.727'

</span><span style="color: blue">DECLARE </span><span style="color: teal">@begin_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">) = (</span><span style="color: blue">select </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'smallest greater than'</span><span style="color: gray">, </span><span style="color: teal">@begin_time</span><span style="color: gray">))
</span><span style="color: blue">DECLARE </span><span style="color: teal">@end_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">) = (</span><span style="color: blue">select </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'largest less than'</span><span style="color: gray">, </span><span style="color: teal">@end_time</span><span style="color: gray">))
</span><span style="color: blue">SELECT </span><span style="color: gray">*
</span><span style="color: blue">FROM </span><span style="color: teal">cdc</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_get_net_changes_dbo_TimeLog</span><span style="color: gray">(</span><span style="color: teal">@begin_lsn</span><span style="color: gray">, </span><span style="color: teal">@end_lsn</span><span style="color: gray">, </span><span style="color: red">'all'</span><span style="color: gray">)
</span><span style="color: blue">WHERE </span><span style="color: teal">UserId </span><span style="color: gray">= </span>1
</pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image55.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb54.png" width="658" height="69"></a></p>
<p>Now I filtered to only show changes for UserId = 1, and only up until right before the time when the wrong data was entered. This is actually the data as we would like to revert back to. Remember, that we don’t want to change anything for UserId = 2!</p>
<p>The way we can do this, is by using a MERGE statement, that uses the select above as source, and the TimeLog table as destination. Like this:</p>
<pre class="code"><span style="color: green">--Reset UserId = 1 to 2012-03-05 19:38:04.727
</span><span style="color: blue">DECLARE </span><span style="color: teal">@UserId </span><span style="color: blue">INT </span><span style="color: gray">= </span>1
<span style="color: blue">DECLARE </span><span style="color: teal">@begin_time </span><span style="color: blue">datetime </span><span style="color: gray">= </span><span style="color: magenta">GETDATE</span><span style="color: gray">()-</span>1
<span style="color: blue">DECLARE </span><span style="color: teal">@end_time </span><span style="color: blue">datetime </span><span style="color: gray">= </span><span style="color: red">'2012-03-05 19:38:04.727'

</span><span style="color: blue">DECLARE </span><span style="color: teal">@begin_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">) = (</span><span style="color: blue">select </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'smallest greater than'</span><span style="color: gray">, </span><span style="color: teal">@begin_time</span><span style="color: gray">))
</span><span style="color: blue">DECLARE </span><span style="color: teal">@end_lsn </span><span style="color: blue">binary</span><span style="color: gray">(</span>10<span style="color: gray">) = (</span><span style="color: blue">select </span><span style="color: green">sys</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_map_time_to_lsn</span><span style="color: gray">(</span><span style="color: red">'largest less than'</span><span style="color: gray">, </span><span style="color: teal">@end_time</span><span style="color: gray">))

</span><span style="color: blue">SET IDENTITY_INSERT </span><span style="color: teal">TimeLog </span><span style="color: blue">ON
MERGE INTO </span><span style="color: teal">TimeLog tgt
</span><span style="color: blue">USING </span><span style="color: gray">(
    </span><span style="color: blue">SELECT </span><span style="color: gray">*
    </span><span style="color: blue">FROM </span><span style="color: teal">cdc</span><span style="color: gray">.</span><span style="color: teal">fn_cdc_get_net_changes_dbo_TimeLog</span><span style="color: gray">(</span><span style="color: teal">@begin_lsn</span><span style="color: gray">, </span><span style="color: teal">@end_lsn</span><span style="color: gray">, </span><span style="color: red">'all'</span><span style="color: gray">)
    </span><span style="color: blue">WHERE </span><span style="color: teal">UserId </span><span style="color: gray">= </span><span style="color: teal">@UserId
</span><span style="color: gray">) </span><span style="color: teal">src </span><span style="color: blue">ON </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">TimeLogId </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeLogId</span><span style="color: teal">
</span><span style="color: blue">WHEN </span><span style="color: gray">MATCHED </span><span style="color: blue">THEN
    </span><span style="color: magenta">UPDATE </span><span style="color: blue">SET
        </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">TimeStart </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeStart</span><span style="color: gray">,
        </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">TimeEnd </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeEnd</span><span style="color: gray">,
        </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: blue">Description </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: blue">Description</span><span style="color: gray">,
        </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">Created </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">Created</span><span style="color: gray">,
        </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">Modified </span><span style="color: gray">= </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">Modified
</span><span style="color: blue">WHEN </span><span style="color: gray">NOT MATCHED </span><span style="color: blue">BY TARGET THEN
    INSERT </span><span style="color: gray">(</span><span style="color: teal">TimeLogId</span><span style="color: gray">, </span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: teal">TimeEnd</span><span style="color: gray">, </span><span style="color: blue">Description</span><span style="color: gray">, </span><span style="color: teal">Created</span><span style="color: gray">, </span><span style="color: teal">Modified</span><span style="color: gray">)
    </span><span style="color: blue">VALUES </span><span style="color: gray">(</span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeLogId</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">UserId</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeStart</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">TimeEnd</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: blue">Description</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">Created</span><span style="color: gray">, </span><span style="color: teal">src</span><span style="color: gray">.</span><span style="color: teal">Modified</span><span style="color: gray">)
</span><span style="color: blue">WHEN </span><span style="color: gray">NOT MATCHED </span><span style="color: blue">BY </span><span style="color: gray">SOURCE AND </span><span style="color: teal">tgt</span><span style="color: gray">.</span><span style="color: teal">UserId </span><span style="color: gray">= </span><span style="color: teal">@UserId </span><span style="color: blue">THEN
    DELETE</span><span style="color: gray">;
</span><span style="color: blue">SET IDENTITY_INSERT </span><span style="color: teal">TimeLog </span><span style="color: blue">OFF
GO
</span></pre>
<p>&nbsp;</p>
<ol>
<li>The select in the USING part, is the same as the one we just saw. I’m joining the source and target on TimeLogId. If the clause matches, then we simply update all the columns of the target (TimeLog table) to the values from the source (the CDC data).</li>
<li>The rows that exists in the source, but not the target, is being inserted (notice the IDENTITY_INSERT at the top).</li>
<li>The rows that does not exist in the source, but is present in the target and has UserId = 1 is deleted.</li>
</ol>
<p>This is just a basic text book MERGE statement, so no fancy thing here.</p>
<p>Now let’s see the data available in TimeLog:</p>
<pre class="code"><span style="color: blue">SELECT </span><span style="color: gray">* </span><span style="color: blue">FROM </span><span style="color: teal">TimeLog
</span></pre>
<p>&nbsp;</p>
<p><a href="http://www.geniiius.com/wp-content/uploads/image56.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.geniiius.com/wp-content/uploads/image_thumb55.png" width="601" height="108"></a></p>
<p>All the registrations for UserId = 2 is still available, but the last two changes for UserId = 1 is gone. That was the wrong update on the “1st work day”, as well as the “3rd work day”. </p>
<p>If we wan’t to perform a redo (an undo of the rollback), then we simply need to execute the exact same code, but use the EndTime from right before we did the rollback. Simple, right? <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile11.png"></p>
<h3>The conclusion</h3>
<p>The solution I came up with, actually solved the problem. But I haven’t done any testing using huge data volumes. And since I have absolutely no real world experience using CDC, I cannot say if this idea is truly stupid, or if it actually might work. I haven’t considered how the undo feature should be build using transactions to ensure integrity, so the solution will probably be a bit more complex than the one above. </p>
<p>But at least now I have an idea what CDC is and what it might be used for, and hopefully you have too <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smiley" src="http://www.geniiius.com/wp-content/uploads/wlEmoticon-smile11.png"></p>
]]></content:encoded>
			<wfw:commentRss>http://www.geniiius.com/blog/how-to-use-change-data-capture-cdc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

