{"id":783,"date":"2009-10-07T13:27:00","date_gmt":"2009-10-07T13:27:00","guid":{"rendered":"\/blogs\/paul\/post\/New-script-is-that-database-REALLY-in-the-FULL-recovery-mode.aspx"},"modified":"2017-04-13T09:54:28","modified_gmt":"2017-04-13T16:54:28","slug":"new-script-is-that-database-really-in-the-full-recovery-mode","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/","title":{"rendered":"New script: is that database REALLY in the FULL recovery mode?"},"content":{"rendered":"<p>One of the perennial problems facing both experienced and involuntary DBAs is how to tell whether a database is really in the Full recovery model or not? This is complicated by the fact that when you switch a database into the Full recovery mode, it actually behaves as if it&#8217;s in the Simple recovery mode until the log backup chain is established (this is commonly called being in &#8216;pseudo-Simple&#8217;).<\/p>\n<p>It&#8217;s a problem for several reasons:<\/p>\n<p>1) if the database is really in the Full recovery model then log backups must be taken so the log can clear\/truncate properly and it doesn&#8217;t grow out of control<\/p>\n<p>2) if the database is in the Full recovery model but the log backup chain has been broken (or not established at all since the database was created) then log backups are not possible (except for the yuckiness in SQL 2000 when log backups would succeed without complaint but be totally useless during disaster recovery)<\/p>\n<p>I don&#8217;t know of any script to easily determine whether a database is really in the Full recovery mode, so I knocked one together &#8211; and I present it here for you to use.<\/p>\n<p>The trick to the script is finding the last LSN that&#8217;s been backed up for the database. if this is non-NULL, then a log backup chain exists and the database is really in the Full recovery mode. This is stored in the <em>dbi_dbbackupLSN<\/em> field in the database boot page (see <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/search-engine-qa-20-boot-pages-and-boot-page-corruption\/\">Search Engine Q&amp;A #20: Boot pages, and boot page corruption<\/a>) but also nicely available in the DMV <em>sys.database_recovery_status<\/em>.<\/p>\n<p>I&#8217;ve tested this on 2005 SP3 and 2008 SP1.<\/p>\n<p>Note that this doesn&#8217;t work on SQL 2000 &#8211; I&#8217;ve poked around and can&#8217;t find a way to get at the LSN without reading the boot page directly, which can&#8217;t be done gracefully inside a function &#8211; I&#8217;ll leave that as an exercise for you. You&#8217;d expect the <em>IsTruncLog<\/em> property returned by <em>DATABASEPROPERTY<\/em> to be correct when the database is in pseudo-Simple, but it&#8217;s not unfortunately.<\/p>\n<p>Here are some test cases for the script:<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nCREATE DATABASE &#x5B;SimpleModeDB];\r\nCREATE DATABASE &#x5B;BulkLoggedModeDB];\r\nCREATE DATABASE &#x5B;FullModeDB];\r\nGO\r\n\r\nALTER DATABASE &#x5B;SimpleModeDB] SET RECOVERY SIMPLE;\r\nALTER DATABASE &#x5B;BulkLoggedModeDB] SET RECOVERY BULK_LOGGED;\r\nALTER DATABASE &#x5B;FullModeDB] SET RECOVERY FULL;\r\nGO\r\n\r\nSELECT\r\n    &#x5B;Name],\r\n    msdb.dbo.SQLSkillsIsReallyInFullRecovery (&#x5B;Name]) AS N'ReallyInFULL'\r\nFROM\r\n    sys.databases\r\nWHERE\r\n    &#x5B;Name] LIKE N'%ModeDB';\r\nGO\r\n<\/pre>\n<pre class=\"brush: plain; gutter: false; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nName\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ReallyInFULL\r\n----------------- -------------\r\nSimpleModeDB\u00a0\u00a0\u00a0\u00a0\u00a0 0\r\nBulkLoggedModeDB\u00a0 0\r\nFullModeDB\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0\r\n<\/pre>\n<p>This makes sense &#8211; the new <em>FullModeDB<\/em> database is still in pseudo-Simple. Now what if we take a full database backup?<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nBACKUP DATABASE &#x5B;FullModeDB]\r\nTO DISK = N'C:SQLskillsFullModeDB.bck'\r\nWITH INIT;\r\nGO\r\nSELECT msdb.dbo.SQLSkillsIsReallyInFullRecovery ('FullModeDB') AS N'ReallyInFULL';\r\nGO\r\n<\/pre>\n<pre class=\"brush: plain; gutter: false; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nProcessed 152 pages for database 'FullModeDB', file 'FullModeDB' on file 1.\r\nProcessed 1 pages for database 'FullModeDB', file 'FullModeDB_log' on file 1.\r\nBACKUP DATABASE successfully processed 153 pages in 0.230 seconds (5.449 MB\/sec).\r\n\r\nReallyInFULL\r\n------------\r\n1\r\n<\/pre>\n<p>Perfect. Now what about switching it back to Simple and back to Full again?<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nALTER DATABASE &#x5B;FullModeDB] SET RECOVERY SIMPLE;\r\nALTER DATABASE &#x5B;FullModeDB] SET RECOVERY FULL;\r\nGO\r\nSELECT msdb.dbo.SQLSkillsIsReallyInFullRecovery ('FullModeDB') AS N'ReallyInFULL';\r\nGO\r\n<\/pre>\n<pre class=\"brush: plain; gutter: false; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nReallyInFULL\r\n------------\r\n0\r\n<\/pre>\n<p>Just as we expect &#8211; the log backup chain has been broken and the database is back to pseudo-Simple again.<\/p>\n<p>Now what if we restart the log backup chain using a full database backup?<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nBACKUP DATABASE &#x5B;FullModeDB]\r\nTO DISK = N'C:SQLskillsFullModeDB.bck'\r\nWITH INIT;\r\nGO\r\nSELECT msdb.dbo.SQLSkillsIsReallyInFullRecovery ('FullModeDB') AS N'ReallyInFULL';\r\nGO\r\n<\/pre>\n<pre class=\"brush: plain; gutter: false; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nProcessed 152 pages for database 'FullModeDB', file 'FullModeDB' on file 1.\r\nProcessed 1 pages for database 'FullModeDB', file 'FullModeDB_log' on file 1.\r\nBACKUP DATABASE successfully processed 153 pages in 0.095 seconds (13.193 MB\/sec).\r\n\r\nReallyInFULL\r\n------------\r\n1\r\n<\/pre>\n<p>Perfect. Now what about if we break the chain and try to restart it using a differential database backup?<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nALTER DATABASE &#x5B;FullModeDB] SET RECOVERY SIMPLE;\r\nALTER DATABASE &#x5B;FullModeDB] SET RECOVERY FULL;\r\nGO\r\nBACKUP DATABASE &#x5B;FullModeDB]\r\nTO DISK = N'C:SQLskillsFullModeDB_diff.bck'\r\nWITH INIT, DIFFERENTIAL;\r\nGO\r\nSELECT msdb.dbo.SQLSkillsIsReallyInFullRecovery ('FullModeDB') AS N'ReallyInFULL';\r\nGO\r\n<\/pre>\n<pre class=\"brush: plain; gutter: false; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nProcessed 40 pages for database 'FullModeDB', file 'FullModeDB' on file 1.\r\nProcessed 1 pages for database 'FullModeDB', file 'FullModeDB_log' on file 1.\r\nBACKUP DATABASE WITH DIFFERENTIAL successfully processed 41 pages in 0.080 seconds (4.192 MB\/sec).&lt;\/span&gt;\r\n\r\nReallyInFULL\r\n------------\r\n1\r\n<\/pre>\n<p>Perfect &#8211; that works too, as I&#8217;d expect. You may wonder why a differential backup works &#8211;\u00a0either a full or differential\u00a0backup will work as\u00a0they bridge the LSN gap since the last full or differential backup before the log backup chain was broken &#8211; both of these backups include transaction log &#8211; see <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/more-on-how-much-transaction-log-a-full-backup-includes\/\">More on how much transaction log a full backup includes<\/a>.<\/p>\n<p>And here&#8217;s the script itself &#8211; enjoy!<\/p>\n<pre class=\"brush: sql; title: ; toolbar: true; wrap-lines: true; notranslate\" title=\"\">\r\nUSE &#x5B;msdb];\r\nGO\r\n\r\nIF EXISTS (SELECT * FROM sys.objects WHERE &#x5B;name] = N'SQLskillsIsReallyInFullRecovery')\r\n    DROP FUNCTION &#x5B;SQLskillsIsReallyInFullRecovery];\r\nGO\r\n\r\nCREATE FUNCTION &#x5B;SQLskillsIsReallyInFullRecovery] (\r\n    @DBName sysname)\r\nRETURNS BIT\r\nAS\r\nBEGIN\r\n    DECLARE @IsReallyFull\u00a0\u00a0BIT;\r\n    DECLARE @LastLogBackupLSN\u00a0NUMERIC (25,0);\r\n    DECLARE @RecoveryModel\u00a0\u00a0TINYINT;\r\n\r\n    SELECT\r\n        @LastLogBackupLSN = &#x5B;last_log_backup_lsn]\r\n    FROM\r\n        sys.database_recovery_status\r\n    WHERE\r\n        &#x5B;database_id] = DB_ID (@DBName);\r\n\r\n    SELECT\r\n        @RecoveryModel = &#x5B;recovery_model]\r\n    FROM\r\n        sys.databases\r\n    WHERE\r\n        &#x5B;database_id] = DB_ID (@DBName);\r\n\r\n    IF (@RecoveryModel = 1 AND @LastLogBackupLSN IS NOT NULL)\r\n        SELECT @IsReallyFull = 1\r\n    ELSE\r\n        SELECT @IsReallyFull = 0;\r\n\r\n    RETURN (@IsReallyFull);\r\nEND;\r\nGO\r\n<\/pre>\n<p>Edwin Sarmiento has published a PowerShell script that does the same thing &#8211; see <a href=\"https:\/\/www.mssqltips.com\/sqlservertip\/2974\/check-if-a-sql-server-database-is-in-pseudosimple-recovery-model-using-windows-powershell\/\" target=\"_blank\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the perennial problems facing both experienced and involuntary DBAs is how to tell whether a database is really in the Full recovery model or not? This is complicated by the fact that when you switch a database into the Full recovery mode, it actually behaves as if it&#8217;s in the Simple recovery mode [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,31,38,52,98],"tags":[],"class_list":["post-783","post","type-post","status-publish","format-standard","hentry","category-backuprestore","category-database-maintenance","category-example-scripts","category-involuntary-dba","category-transaction-log"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal\" \/>\n<meta property=\"og:description\" content=\"One of the perennial problems facing both experienced and involuntary DBAs is how to tell whether a database is really in the Full recovery model or not? This is complicated by the fact that when you switch a database into the Full recovery mode, it actually behaves as if it&#8217;s in the Simple recovery mode [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/\" \/>\n<meta property=\"og:site_name\" content=\"Paul S. Randal\" \/>\n<meta property=\"article:published_time\" content=\"2009-10-07T13:27:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-04-13T16:54:28+00:00\" \/>\n<meta name=\"author\" content=\"Paul Randal\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Paul Randal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/\",\"name\":\"New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\"},\"datePublished\":\"2009-10-07T13:27:00+00:00\",\"dateModified\":\"2017-04-13T16:54:28+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"New script: is that database REALLY in the FULL recovery mode?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\",\"name\":\"Paul S. Randal\",\"description\":\"In Recovery...\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\",\"name\":\"Paul Randal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"caption\":\"Paul Randal\"},\"sameAs\":[\"http:\/\/3.209.169.194\/blogs\/paul\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/","og_locale":"en_US","og_type":"article","og_title":"New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal","og_description":"One of the perennial problems facing both experienced and involuntary DBAs is how to tell whether a database is really in the Full recovery model or not? This is complicated by the fact that when you switch a database into the Full recovery mode, it actually behaves as if it&#8217;s in the Simple recovery mode [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/","og_site_name":"Paul S. Randal","article_published_time":"2009-10-07T13:27:00+00:00","article_modified_time":"2017-04-13T16:54:28+00:00","author":"Paul Randal","twitter_misc":{"Written by":"Paul Randal","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/","name":"New script: is that database REALLY in the FULL recovery mode? - Paul S. Randal","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website"},"datePublished":"2009-10-07T13:27:00+00:00","dateModified":"2017-04-13T16:54:28+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/new-script-is-that-database-really-in-the-full-recovery-mode\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/paul\/"},{"@type":"ListItem","position":2,"name":"New script: is that database REALLY in the FULL recovery mode?"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/","name":"Paul S. Randal","description":"In Recovery...","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce","name":"Paul Randal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","caption":"Paul Randal"},"sameAs":["http:\/\/3.209.169.194\/blogs\/paul"],"url":"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/783","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/comments?post=783"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/783\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/media?parent=783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/categories?post=783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/tags?post=783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}