{"id":903,"date":"2011-03-08T16:30:44","date_gmt":"2011-03-08T14:30:44","guid":{"rendered":"https:\/\/www.sqlinthewild.co.za\/?p=903"},"modified":"2011-03-20T23:12:12","modified_gmt":"2011-03-20T21:12:12","slug":"full-backups-the-log-chain-and-the-copy_only-option","status":"publish","type":"post","link":"https:\/\/www.sqlinthewild.co.za\/index.php\/2011\/03\/08\/full-backups-the-log-chain-and-the-copy_only-option\/","title":{"rendered":"Full backups, the log chain and the COPY_ONLY option."},"content":{"rendered":"<p>There have been a large number of posts made regarding the interaction between full database backups and the log chain (<a href=\"http:\/\/sqlskills.com\/BLOGS\/PAUL\/post\/Misconceptions-around-the-log-and-log-backups-how-to-convince-yourself.aspx\">like this one<\/a>). However there still seems to be a lot of confusion around regarding how they interact. I doubt I can clear up the confusion with yet another blog post, but I&#8217;ll try.<\/p>\n<p>One that seems to come up now and again is the COPY_ONLY Option on backups. Typically the comment is something like &#8216;Use the COPY_ONLY option when taking ad-hoc full backups so that you don&#8217;t impact the log backups.&#8217; Now we know from the blog posts linked above that full backups don&#8217;t ever break the log chain (and I&#8217;m not going to run yet more tests to prove it) so what is the copy only option there for?<\/p>\n<p>Books Online states the following regarding the COPY_ONLY option for backups &#8211; &#8220;Specifies that the backup is a copy-only backup, which does not affect the normal sequence of backups. A copy-only backup is created independently of your regularly scheduled, conventional backups. A copy-only backup does not affect your overall backup and restore procedures for the database.&#8221;<\/p>\n<p>Well, that doesn&#8217;t clear things up much. It does however go on to say this: &#8220;When used with BACKUP DATABASE, the COPY_ONLY option creates a full backup that cannot serve as a differential base. The differential bitmap is not updated, and differential backups behave as if the copy-only backup does not exist. Subsequent differential backups use the most recent conventional full backup as their base.&#8221;<\/p>\n<p>So it&#8217;s not the log chain that copy only is there to not affect, it&#8217;s the differential base. Let&#8217;s test and see how it works.<\/p>\n<p><!--more--><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">CREATE DATABASE TestingBackups\r\nGO\r\n\r\nUSE TestingBackups\r\nGO\r\n\r\nCREATE TABLE Testing (\r\nID INT IDENTITY PRIMARY KEY,\r\nSomeValue CHAR(4)\r\n);\r\nGO\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Full1.bak'\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('abc')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff1.bak' WITH DIFFERENTIAL\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('def')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Full2.bak'\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('ghi')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH DIFFERENTIAL\r\nGO<\/pre>\n<p>Right, so that&#8217;s a database with two full backups and two differential backups and a couple data changes in between. Let&#8217;s drop the database and test some restore strategies. The goal is to restore the database to the point that it was at the time the second differential backup was taken.<\/p>\n<p>First the obvious route. Full backup 2 and differential backup 2.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">RESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Full2.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups WITH RECOVERY<\/pre>\n<p>That works. That&#8217;s the most obvious and likely the one that will be used the most. What happens though if we don&#8217;t have full backup 2? What if it was a full backup that an evil developer took without asking, used to restore a development\/test database somewhere and then deleted the backup file?<\/p>\n<p>There are two options there that might work:<\/p>\n<ul>\n<li>Full backup 1 and differential backup 2 (differential backups are cumulative aren&#8217;t they?)<\/li>\n<li>Full backup 1, differential backup 1 and then differential backup 2.<\/li>\n<\/ul>\n<p>Option 1<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">RESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Full1.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups WITH RECOVERY<\/pre>\n<p>Well that didn&#8217;t work\u2026<\/p>\n<blockquote><p>Msg 3136, Level 16, State 1, Line 1<br \/>\nThis differential backup cannot be restored because the database has not been restored to the correct earlier state.<br \/>\nMsg 3013, Level 16, State 1, Line 1<br \/>\nRESTORE DATABASE is terminating abnormally.<\/p><\/blockquote>\n<p>Option 2<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">RESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Full1.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff1.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups WITH RECOVERY<\/pre>\n<p>That didn&#8217;t work either.<\/p>\n<blockquote><p>Msg 3136, Level 16, State 1, Line 1<br \/>\nThis differential backup cannot be restored because the database has not been restored to the correct earlier state.<br \/>\nMsg 3013, Level 16, State 1, Line 1<br \/>\nRESTORE DATABASE is terminating abnormally.<\/p><\/blockquote>\n<p>Differential backup 1 restored fine, differential backup 2 didn&#8217;t. The reason is that, unlike log backups, differential backups are affected by full backups. Specifically, a differential backup is based on the last full backup that ran before it. If an ad-hoc full backup is taken, any differential run after that is based on the ad-hoc full backup and not the one run as part of the standard backup plan. Not fun if a developer runs one then deletes the backup file when it&#8217;s no longer needed.<\/p>\n<p>This is what copy-only affects when specified on a full backup. A full backup run with copy-only does not change the differential base and does not reset the list of extents changed since the last full backup. Hence an ad-hoc full database backup, if specified with the COPY_ONLY option, won&#8217;t cause administrators unpleasant surprises when test restores are done or a disaster occurs and a full restore is necessary.<\/p>\n<p>Let&#8217;s drop that test database and recreate it using COPY_ONLY on the second full backup.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">CREATE DATABASE TestingBackups\r\nGO\r\n\r\nUSE TestingBackups\r\nGO\r\n\r\nCREATE TABLE Testing (\r\nID INT IDENTITY PRIMARY KEY,\r\nSomeValue CHAR(4)\r\n);\r\nGO\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Full1.bak'\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('abc')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff1.bak' WITH DIFFERENTIAL\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('def')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Full2.bak' WITH COPY_ONLY\r\nGO\r\n\r\nINSERT INTO Testing (SomeValue)\r\nVALUES ('ghi')\r\n\r\nBACKUP DATABASE TestingBackups TO DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH DIFFERENTIAL\r\nGO<\/pre>\n<p>Now the restore path using full backup 1 and differential backup 2 does work.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">RESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Full1.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups FROM DISK = 'C:\\Databases\\Backup\\TestingBackups_Diff2.bak' WITH NORECOVERY\r\nGO\r\nRESTORE DATABASE TestingBackups WITH RECOVERY<\/pre>\n<blockquote><p>Processed 168 pages for database &#8216;TestingBackups&#8217;, file &#8216;TestingBackups&#8217; on file 1.<br \/>\nProcessed 5 pages for database &#8216;TestingBackups&#8217;, file &#8216;TestingBackups_log&#8217; on file 1.<br \/>\nRESTORE DATABASE successfully processed 173 pages in 0.215 seconds (6.286 MB\/sec).<br \/>\nProcessed 64 pages for database &#8216;TestingBackups&#8217;, file &#8216;TestingBackups&#8217; on file 1.<br \/>\nProcessed 1 pages for database &#8216;TestingBackups&#8217;, file &#8216;TestingBackups_log&#8217; on file 1.<br \/>\nRESTORE DATABASE successfully processed 65 pages in 0.103 seconds (4.873 MB\/sec).<br \/>\nRESTORE DATABASE successfully processed 0 pages in 0.371 seconds (0.000 MB\/sec).<\/p><\/blockquote>\n<p>With that out of the way, the question still remains as to whether COPY_ONLY has anything to do with log backups or the log chain. Books online also says this about them: &#8220;When used with BACKUP LOG, the COPY_ONLY option creates a copy-only log backup, which does not truncate the transaction log. The copy-only log backup has no effect on the log chain, and other log backups behave as if the copy-only backup does not exist.&#8221;<\/p>\n<p>So COPY_ONLY changes the effect a backup has on the log chain only when specified on a transaction log backup, not on full databases backups. Useful if you need an ad-hoc log backup for something.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There have been a large number of posts made regarding the interaction between full database backups and the log chain (like this one). However there still seems to be a lot of confusion around regarding how they interact. I doubt&#8230; <a class=\"read-more-button\" href=\"https:\/\/www.sqlinthewild.co.za\/index.php\/2011\/03\/08\/full-backups-the-log-chain-and-the-copy_only-option\/\">(Read more)<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[20,15,16],"tags":[],"class_list":["post-903","post","type-post","status-publish","format-standard","hentry","category-admin","category-sql-server","category-syndication"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7h6n-ez","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/903","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=903"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/903\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=903"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/categories?post=903"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/tags?post=903"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}