<?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>Edwin M Sarmiento&gt;I wish this was available years back &#8211; SQL Server 2005 Always On Technologies Part 2 &#8211; Edwin M Sarmiento</title>
	<atom:link href="https://www.edwinmsarmiento.com/i-wish-this-was-available-years-back-sql-server-2005-always-on-technologies-part-2/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.edwinmsarmiento.com</link>
	<description>Intentional Excellence</description>
	<lastBuildDate>Mon, 13 Apr 2026 21:00:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">84283043</site>		<item>
		<title>&gt;I wish this was available years back &#8211; SQL Server 2005 Always On Technologies Part 2</title>
		<link>https://www.edwinmsarmiento.com/i-wish-this-was-available-years-back-sql-server-2005-always-on-technologies-part-2/</link>
		<comments>https://www.edwinmsarmiento.com/i-wish-this-was-available-years-back-sql-server-2005-always-on-technologies-part-2/#respond</comments>
		<pubDate>Mon, 01 Oct 2007 06:36:00 +0000</pubDate>
		<dc:creator>Edwin M Sarmiento</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://bassplayerdoc.wordpress.com/2007/10/01/i-wish-this-was-available-years-back-sql-server-2005-always-on-technologies-part-2</guid>

				<description><![CDATA[&#62;One of the most underestimated feature of SQL Server is the FULL RECOVERY model in the database options. Database recovery models determine how much data loss is acceptable in case of a failure and what types of backup and restore functions are allowed. This has been an option which you can trace back from the [&#8230;]]]></description>
					<content:encoded><![CDATA[<p>&gt;<span style="font-family:lucida grande;"><span style="font-family:arial;">One of the most underestimated feature of SQL Server is the <strong><span style="font-size:85%;">FULL RECOVERY</span></strong> model in the database options. Database recovery models determine how much data loss is acceptable in case of a failure and what types of backup and restore functions are allowed. This has been an option which you can trace back from the earlier versions of SQL Server. We will not be going in detail with the different recovery models but it would be best to know that if you have a mission-critical database, it should be configured to use the <strong><span style="font-size:85%;">FULL</span></strong> recovery model. A full description of the different recovery models for SQL Server 2000 (whch is also applicable to 2005) can be found in this <a href="http://msdn2.microsoft.com/en-us/library/aa173678(SQL.80).aspx">MSDN article</a>. Let&#8217;s look at the same scenario we had in the first part of this series. The <strong><span style="font-size:85%;">[Order Details]</span></strong> table, for example, in the Northwind database can be dropped successfully any time even if referential integrity is enforced in the database (try running the <strong><span style="font-size:85%;">DROP TABLE [Order Details]</span></strong> comand and see what happens). Now, as I have mentioned, a mission-critical database should be configured with <strong><span style="font-size:85%;">FULL</span></strong> recovery model combined with regular backups, either full database backups or a combination of full with differential and/or transaction log backups. So, I am assumming that you have at least a full database backup on a regular basis.</span></span></p>
<p></p>
<ol>
<li><span style="font-family:lucida grande;"><span style="font-family:arial;"><strong>Contain the disaster</strong></span></span></li>
<p><span style="font-family:lucida grande;"><span style="font-family:arial;">The first thing that you need to do when a user accidentally drops a table (or any object) in your database is to contain the disaster. You can do this by setting the database option to only be accessed by the <strong><span style="font-size:85%;">dbo</span></strong>. You can do this either thru <strong><span style="font-size:85%;">SQL</span></strong> <strong><span style="font-size:85%;">Server Management Studio</span></strong> or running the <strong><span style="font-size:85%;">ALTER DATABASE</span></strong> command</span></span><br /><span style="font-size:85%;"><strong><span style="font-family:georgia;"><span style="color:#000099;">ALTER DATABASE</span> Northwind<br /><span style="color:#000099;">SET RESTRICTED_USER</span><br /><span style="color:#000099;">WITH ROLLBACK</span> IMMEDIATE</span></strong><br /></span><span style="font-family:arial;">The <strong><span style="font-size:85%;">WITH ROLLBACK IMMEDIATE</span></strong> option in the <strong><span style="font-size:85%;">ALTER DATABASE</span></strong> command specifies to rollback all active transactions immediately while setting the access mode to <strong><span style="font-size:85%;">RESTRICTED_USER</span></strong>, which in this case is the <strong>dbo</strong>. This will prevent any other user from connecting to the database, of course, with the goal of getting the database back online with the least amount of downtime.</span></li>
<li><span style="font-family:arial;"><strong>Backup the transaction log</strong></span></li>
<p><span style="font-family:arial;">Since you have configured your database to be in <strong><span style="font-size:85%;">FULL</span></strong> recovery model, you can backup what we call the &#8220;<em>tail of the log</em>&#8221; or the active portion of the transaction log. This will ive you the option to do a point-in-time restoration, the time before the <strong><span style="font-size:85%;">DROP TABLE</span></strong> statement was executed. Since the database is technically offline at this point in time, you do not need to issue a <strong><span style="font-size:85%;">WITH NO_TRUNCATE</span></strong> option in your <strong><span style="font-size:85%;">BACKUP LOG</span></strong> command</span><br /><span style="font-size:85%;"><strong><span style="color:#000099;">BACKUP</span> <span style="color:#cc33cc;">LOG </span>Northwind<br /><span style="color:#000099;">TO DISK</span> = N<span style="color:#cc0000;">&#8216;D:NorthwindLOG.TRN&#8217;</span><br /><span style="color:#000099;">WITH NAME</span> = N<span style="color:#cc0000;">&#8216;Transaction Log Backup&#8217;</span>, <span style="color:#000099;">STATS</span> = 10<br />GO</strong></span><br /><span style="font-family:Arial;">You will need both your full database backup and this transaction log backup to recover the dropped table. </li>
<li></span><span style="font-family:arial;"><strong>Restore the database in RESTRICTED_USER mode from the full database backup and the transaction log backup</strong></span><br /><span style="font-family:Arial;">Since you have already got a full database and tail-of-the-log backup, you can now restore your database to a point before the table was dropped. This is going to be a bit tricky as you do not know exactly when the table was dropped (even if the developer called you up when the event happened, it would probably take minutes to log on to the server, open up your favorite query tool &#8211; be it Query Analyzer or Management Studio &#8211; and go thru steps 1 and 2 above). To make it a bit faster, just restore to a known good point-in-time just to get the database back online the soonest time possible and worry about trying to find when the table was dropped later.<br /></span><span style="font-family:courier new;"><span style="font-family:georgia;"><strong><span style="font-size:85%;"><span style="color:#000099;">USE master</span><br />GO
<p><span style="color:#000099;">RESTORE DATABASE</span> Northwind<br /><span style="color:#000099;">FROM DISK</span> = N&#8217;<span style="color:#990000;">D:NorthwindFull.bak</span>&#8216;<br /><span style="color:#000099;">WITH NORECOVERY, RESTRICTED_USER</span><br />GO</p>
<p><span style="color:#000099;">RESTORE</span> <span style="color:#cc33cc;">LOG</span> Northwind<br /><span style="color:#000099;">FROM DISK</span> = N&#8217;<span style="color:#990000;">D:NorthwindLOG.TRN</span>&#8216;<br /></span></strong><strong><span style="font-size:85%;"><span style="color:#000099;">WITH RESTRICTED_USER,<br /></span><span style="color:#009900;">&#8212; use a &#8220;known good&#8221; point in time</span><br /><span style="color:#000099;">STOPAT</span> = <span style="color:#990000;">&#8216;2007-09-12 10:13:03.420&#8217;</span>, <span style="color:#000099;">RECOVERY </span><br />GO</span></strong></span><strong><br /></strong><span style="font-family:arial;">We are assumming here that the<strong><span style="font-size:85%;"> [Order Details]</span></strong> table was dropped before September 12, 2007 10:14AM, that&#8217;s why we are taking 10:13:03.420 as a point-in-time restore point. Remember that if we restore to a point where the table has already been dropped, we have to start the restore process again. But we are not done yet. We don&#8217;t know how many transactions have been committed between 10:13:03.420 and 10:14:00.000. On highly transactional databases, say averaging around 500 transactions per second or higher, you come up with around 28,500 transactions within that span of time. If a single transaction is about $0.05, you&#8217;ve lost about $1,425 within that span of time (and now you know the reason why database engineers and administrators get paid well, especially in financial institutions). Notice that the database was restored with the <strong><span style="font-size:85%;">RESTRICTED_USER</span></strong> option. This means that the database is still inaccessible from external users. This is because we are not done yet. </span></span></li>
<li><span style="font-family:arial;"><strong>Create a snapshot of the restored database and create a gap to store the recovered records later</strong></span></li>
<p><span style="font-family:arial;">We create a snapshot of the restored database which we will use for analyzing the records that need to be restored after getting our database back online. Remember, we only restored the database from a good point in time but probably way back before the table was dropped. That small difference is what we need to restore once the database is online. To create the database snapshot, we use the <strong><span style="font-size:85%;">CREATE DATABASE </span></strong>command</span><br /><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">CREATE DATABASE</span> Northwind_RestorePointSnapshot<br /><span style="color:#000099;">ON</span><br />( <span style="color:#000099;">NAME</span> = N<span style="color:#990000;">&#8216;Northwind&#8217;</span>,<br /><span style="color:#000099;">FILENAME</span> = N<span style="color:#990000;">&#8216;C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLDATANorthwind_RestorePontSnapshot.mdf_snap&#8217;</span>)<br /><span style="color:#000099;">AS SNAPSHOT OF</span> [Northwind]</strong></span><br /><span style="font-family:Arial;">The snapshot should be in the same instance as the reference database. I will not be digging deeper into database snapshots in this entry but will probably spend some time in the future discussing database snapshots in SQL Server 2005. To create a gap in the <strong><span style="font-size:85%;">[Order Details]</span></strong> table to store the recovered records later, we need to execute a <strong><span style="font-size:85%;">DBCC CHECKIDENT</span></strong> command on the <strong><span style="font-size:85%;">[Order Details]</span></strong> table. This is assumming we have an <strong><span style="font-size:85%;">IDENTITY</span></strong> column defined in the table, which is usually the case (although the [Order Details] table in the Northwind database does not have an identity column, let&#8217;s assume it does. Or better yet, add an identity column. I added one just for this purpose named <strong><span style="font-size:85%;">OrdDetID</span></strong>).<br /></span><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">DBCC</span> CHECKIDENT (<span style="color:#990000;">&#8216;[Order Details]&#8217;</span>) <span style="color:#009900;">&#8212; we will get the number of rows we have</span><br />GO<br /><span style="color:#000099;">USE</span> Northwind</strong></span><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">GO</span><br /></strong><strong><span style="color:#009900;">&#8212; we will use a value big enough to insert the recovered records later<br /></span><span style="color:#000099;">DBCC</span> CHECKIDENT (<span style="color:#990000;">&#8216;[Order Details]&#8217;</span>, RESEED, 4200000)<br /></strong><strong>GO</strong></span><br /><span style="font-family:arial;">The <strong><span style="font-size:85%;">RESEED </span></strong>option specifies that the current identity value should be corrected. Let&#8217;s say we get a value of <strong><span style="font-size:85%;">4000000</span></strong> in the first <strong><span style="font-size:85%;">DBCC CHECKIDENT</span></strong> command, we can create a gap of about <strong><span style="font-size:85%;">200000</span></strong> to insert the recovered records later on (which explains the value of <strong><span style="font-size:85%;">4200000</span></strong>). We don&#8217;t really care how big the gap is, what&#8217;s more important is we have enough space to insert the records and we can get the </span><span style="font-family:arial;">database back online. The next <strong><span style="font-size:85%;">DBCC CHECKIDENT</span></strong> command is to be executed on the original <strong><span style="font-size:85%;">Northwind</span></strong> database as </span><span style="font-family:arial;">this is where we need to create the gap. Once we&#8217;re done with this, we can now get the database back online.<br /></span></p>
<li><span style="font-family:arial;"><strong>Get the database back online</strong></span></li>
<p><span style="font-family:arial;">By now, we are ready to get the database back online. We can run the <strong><span style="font-size:85%;">ALTER DATABASE</span></strong> command or use <strong><span style="font-size:85%;">SQL Server Management Studio</span></strong> to do this.<br /></span><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">USE</span> master<br />GO</p>
<p><span style="color:#000099;">ALTER DATABASE</span> Northwind<br /><span style="color:#000099;">SET MULTI_USER</span></strong><br /><span style="font-family:arial;font-size:100%;">Now that the database is back online, we can start investigating the damaged data. </span></span></li>
<li><span style="font-family:arial;"><strong>Restore the database with a different name for investigation</strong></span><br /><span style="font-family:arial;">Since the production database is up and running, we can now go back and spend all the time we have to investigate the gap between what is and what should be in the production. Remember that we only restored the production database to a good known point in time. We have to identify the records that are still in the tail-of-the log than needs to be brought back to the production database. To restore the database backup to a different name,</span><br /><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">USE master
<p>RESTORE DATABASE</span> [Northwind_Investigate]<br /><span style="color:#000099;">FROM DISK</span> = N<span style="color:#990000;">&#8216;D:InvestigateNorthwindBackup.bak&#8217; </span><br /><span style="color:#000099;">WITH MOVE</span> <span style="color:#990000;">N&#8217;SalesDBData&#8217;</span> <span style="color:#000099;">TO</span> N<span style="color:#990000;">&#8216;C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLDATANorthwindData_Investigate.mdf&#8217;</span>,<br /><span style="color:#000099;">MOVE </span>N<span style="color:#990000;">&#8216;SalesDBLog&#8217;</span> <span style="color:#000099;">TO</span> N<span style="color:#990000;">&#8216;C:Program FilesMicrosoft SQL ServerMSSQL.1MSSQLDATANorthwindLog_Investigate.ldf&#8217;</span>,<br /><span style="color:#000099;">STANDBY </span>= N<span style="color:#990000;">&#8216;D:InvestigateNorthwind_UNDO.bak&#8217;</span>,<br /><span style="color:#000099;">STOPAT</span> = <span style="color:#990000;">&#8216;2007-09-12 10:13:03.420&#8217;</span>, <span style="color:#000099;">STATS</span><br />GO</p>
<p><span style="color:#000099;">RESTORE </span><span style="color:#cc33cc;">LOG</span> [Northwind_Investigate]<br />FROM DISK = N<span style="color:#990000;">&#8216;D:InvestigateNorthwindBackup.TRN&#8217;</span><br /><span style="color:#000099;">WITH STANDBY</span> = N<span style="color:#990000;">&#8216;D:InvestigateNorthwind_UNDO.bak&#8217;</span>,<br /><span style="color:#000099;">STOPAT</span> =<span style="color:#990000;">&#8216;2007-09-12 10:13:03.420&#8217;</span>, <span style="color:#000099;">STATS</span><br />GO</strong></span><br /><span style="font-family:arial;"><br />This is exactly what we did in Step #2 except that we are now restoring on a different database. We do the <strong><span style="font-size:85%;">RESTORE LOG</span></strong> command until we come to a point-in-time before the table was dropped. This is a tricky one as it requires patience and attention to detail. If you just went beyond the point-in-time where the table was dropped, you will have to start over again. Play around with the value in the <strong><span style="font-size:85%;">STOPAT</span></strong> option, moving forward either on a per second, per minute or per 5-minute intervals. You decide on the value. The ultimate test to find out whether or not the table has already been dropped is to execute a <strong><span style="font-size:85%;"><span style="color:#000099;">SELECT</span> <span style="color:#cc33cc;">COUNT</span>(*) <span style="color:#000099;">FROM</span> [Order Details]</span></strong> command. If this returned an error stating that the object does not exist, then you have restored to a point-in-time after the table was dropped and you have to repeat the process. Once you know you&#8217;re done, you&#8217;re ready to extract those records and push them to the production database.</span></li>
<li><span style="font-family:arial;"><strong>Identify the records missing in the production database</strong></span><br /><span style="font-family:arial;">Since we have created a gap in the production database using the <strong><span style="font-size:85%;">RESEED</span></strong> option, we can identify how many records are in the investigate database but not in the production. We&#8217;ll use the value we specified in Step #4, 4200000<br /></span><span style="font-family:lucida grande;"><span style="color:#000099;"><br /><span style="font-size:85%;"><span style="color:#009900;">&#8211;identify the number of records in production database before RESEED<br /></span><strong>SELECT</strong></span></span><strong><span style="font-size:85%;"> OrdDetID<br /><span style="color:#000099;">FROM</span> Northwind.dbo.[OrderDetails] <span style="color:#000099;">WHERE</span> OrdDetID&lt;4200000</span></strong><span style="color:#009900;"><br /><span style="font-size:85%;">&#8211;identify the number of records in the investigate database which are not in production<br />&#8211;if we get 4150000 from the first query, we use this value in the WHERE clause</span></span><span style="font-size:85%;"><br /><strong>SELECT</strong></span></span><strong><span style="font-size:85%;"> OrdDetID<br /><span style="color:#000099;">FROM</span> Northwind_Investigate.dbo.[OrderDetails] <span style="color:#000099;">WHERE</span> OrdDetID&gt;4150000</span></span></strong>
<p><span style="font-family:arial;">We&#8217;ll get an idea on the number of records missing in the production database using this aproach. There are a lot of ways to push these records back in the production database and we&#8217;ll look at some of them </span></li>
<li><strong><span style="font-family:arial;">Push the records back from the investigate to the production database </span></strong><br /><span style="font-family:arial;">There are a lot of ways to do this. Let&#8217;s look at some of them. One way is to do an <strong><span style="font-size:85%;">INSERT..SELECT</span></strong> command from the investigate database to the production database. A sample query to do this is shown below.<br /></span><span style="font-family:lucida grande;font-size:85%;"><span style="color:#009900;"><br />&#8211;recover from missing rows<br /></span><strong><span style="color:#000099;">SET IDENTITY_INSERT</span> Northwind.dbo.[Order Details] <span style="color:#000066;">ON</span><br />GO
<p><span style="color:#000099;">INSERT</span> Northwind.dbo.[Order Details]<br /><span style="color:#000099;">SELECT</span> *<br /><span style="color:#000099;">FROM</span> [Northwind_Investigate].dbo.[Order Details] <span style="color:#000099;">AS</span> R<br /><span style="color:#000099;">WHERE</span> R.OrdDetID &gt; 4150000<br />GO</strong></span></p>
<p><span style="font-family:arial;">The problem with this approach is that you are assuming only <span style="font-size:85%;"><strong>INSERT</strong></span> statements were executed between the gap. In reality, we don&#8217;t really know. It could have been a couple of <strong><span style="font-size:85%;">INSERTS, UPDATES</span></strong> and <strong><span style="font-size:85%;">DELETES</span></strong> simultaneously occurring within this span of time which limits your assumption in using this approach. A more appropriate approach is to use the <strong><span style="font-size:85%;"><a href="http://msdn2.microsoft.com/en-us/library/ms162843.aspx">tablediff.exe</a></span></strong> utility. This utility is used to compare the data in two tables for non-convergence, and is particularly useful for troubleshooting non-convergence in a replication topology. Now you might be thinking otherwise as we do not have a replicated environment here. Well, we could think of it as one so we can use this utility. It can generate the corresponding <strong><span style="font-size:85%;">INSERT, UPDATE </span></strong>and <strong><span style="font-size:85%;">DELETE</span></strong> statements to execute to make replicated databases in sync. A full description of this utility is available in <a href="http://msdn2.microsoft.com/en-us/library/ms162843.aspx">MSDN</a>. Now, there are some limitations here. We don&#8217;t know exactly how many tables were affected in a specific disaster. In this particular scenario, we only dealt with a single table being dropped by a user. What if there were more than one table which I believe all of the database I know of have. Since the <strong><span style="font-size:85%;">tablediff</span></strong> utility generates the SQL statements only for a single table, we can create a dynamic SQL statement which will query the <strong><span style="font-size:85%;">sysobjects</span></strong> table (or the <strong><span style="font-size:85%;">sys.objects</span></strong> table in SQL Server 2005) for the names of the tables and generate a tablediff command with all of these parameters derived from extracting the names of the tables. This will be an appropriate approach to synchronize the investigate database and the production database. There is a GUI tool created by the guys from <a href="http://weblogs.sqlteam.com/mladenp/archive/2007/08/10/60279.aspx">SQLTeam.com</a> for those who use this tool often.</span></li>
</ol>
<p><span style="font-family:arial;">You have seen how to take disaster recovery (sometimes known as data recovery) in another level in this article. As I always emphasize, the process is more important than the technology that&#8217;s why I highlighted the process in detail. The technology portion can be extracted from just about anywhere. Having a disaster recovery process is very important. Document your process and have a regular DR drill exercise to prepare you and your team when disaster strikes. In the next article in this series, we will look at other disaster recovery options available in SQL Server 2005</span></p>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/92377218009570869-7717096601572389559?l=bassplayerdoc.blogspot.com' alt='' /></div>
]]></content:encoded>
			

		<wfw:commentRss>https://www.edwinmsarmiento.com/i-wish-this-was-available-years-back-sql-server-2005-always-on-technologies-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
				<post-id xmlns="com-wordpress:feed-additions:1">13</post-id>	</item>
	</channel>
</rss>