{
  "date": "2014-03-23T15:04:39",
  "slug": "the-consequences-of-nologging-in-oracle",
  "link": "https://www.dbi-services.com/blog/the-consequences-of-nologging-in-oracle/",
  "title": {
    "rendered": "The consequences of NOLOGGING in Oracle"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nWhile answering to a <a href=\"https://community.oracle.com/message/12335937#12335937\">question</a> on Oracle forum about NOLOGGING consequences, I provided a test case that deserves a bit more explanation. Nologging operations are good to generate minimal redo on bulk operations (direct-path inserts, index creation/rebuild). But in case we have to restore a backup that was made before the nologging operation, we loose data. And even if we can accept that, we have some manual operations to do.</p>\n<p>Here is the full testcase.</p>\n<p>I create a tablespace and backup it:</p>\n<pre><code><samp></samp>RMAN&gt; create tablespace demo datafile '/tmp/demo.dbf' size 10M; \nStatement processed\nRMAN&gt; backup tablespace demo; \nStarting backup at 23-MAR-14 \nallocated channel: ORA_DISK_1 \nchannel ORA_DISK_1: SID=30 device type=DISK \nchannel ORA_DISK_1: starting full datafile backup set \nchannel ORA_DISK_1: specifying datafile(s) in backup set \ninput datafile file number=00005 name=/tmp/demo.dbf \nchannel ORA_DISK_1: starting piece 1 at 23-MAR-14 \nchannel ORA_DISK_1: finished piece 1 at 23-MAR-14 \npiece handle=/u01/app/oracle/fast_recovery_area/U1/backupset/2014_03_23/o1_mf_nnndf_TAG20140323T160453_9lxy0pfb_.bkp tag=TAG20140323T160453 comment=NONE \nchannel ORA_DISK_1: backup set complete, elapsed time: 00:00:01 \nFinished backup at 23-MAR-14</code></pre>\n<p>I create a table and an index, both in NOLOGGING</p>\n<pre><code><samp></samp>RMAN&gt; create table demo ( dummy not null ) tablespace demo nologging as select * from dual connect by level Statement processed\nRMAN&gt; create index demo on demo(dummy) tablespace demo nologging; \nStatement processed</code></pre>\n<p>Note how I like 12c for doing anything from RMAN&#8230;<br />\nBecause I will need it later, I do a treedump of my index:</p>\n<pre><code><samp></samp>RMAN&gt; begin \n2&gt;  for o in (select object_id from dba_objects where owner=user and object_name='DEMO' and object_type='INDEX') \n3&gt;   loop execute immediate 'alter session set tracefile_identifier=''treedump'' events ''immediate trace name treedump level '||o.object_id||''''; \n4&gt; end loop; \n5&gt; end; \n6&gt; / \nStatement processed</code></pre>\n<p>Here is the content of my treedump trace file:</p>\n<pre><code><samp></samp>----- begin tree dump \nbranch: 0x140008b 20971659 (0: nrow: 2, level: 1) \n   leaf: 0x140008c 20971660 (-1: nrow: 552 rrow: 552) \n   leaf: 0x140008d 20971661 (0: nrow: 448 rrow: 448) \n----- end tree dump</code></pre>\n<p>Because of the nologging, the tablespace is &#8216;unrecoverable&#8217; and we will see what it means.</p>\n<pre><code><samp></samp>RMAN&gt; report unrecoverable; \nReport of files that need backup due to unrecoverable operations \nFile Type of Backup Required Name \n---- ----------------------- ----------------------------------- \n5    full or incremental     /tmp/demo.dbf</code></pre>\n<p>RMAN tells me that I need to do a backup, which is the right thing to do after nologging operations. But here my goal is to show what happens when we have to restore a backup that was done before the nologging operations.</p>\n<p>I want to show that the issue does not only concern the data that I&#8217;ve loaded, but any data that may come later in the blocks that have been formatted by the nologging operation. So I&#8217;m deleteing the rows and inserting a new one.</p>\n<pre><code><samp></samp>2&gt; delete from demo; \nStatement processed\nRMAN&gt; insert into demo select * from dual; \nStatement processed</code></pre>\n<p>Time to restore the tablespace from the backup that has been done before the nologging operation:</p>\n<pre><code><samp></samp>RMAN&gt; alter tablespace demo offline; \nStatement processed\nRMAN&gt; restore tablespace demo; \nStarting restore at 23-MAR-14 \nusing channel ORA_DISK_1\nchannel ORA_DISK_1: starting datafile backup set restore \nchannel ORA_DISK_1: specifying datafile(s) to restore from backup set \nchannel ORA_DISK_1: restoring datafile 00005 to /tmp/demo.dbf \nchannel ORA_DISK_1: reading from backup piece /u01/app/oracle/fast_recovery_area/U1/backupset/2014_03_23/o1_mf_nnndf_TAG20140323T160453_9lxy0pfb_.bkp \nchannel ORA_DISK_1: piece handle=/u01/app/oracle/fast_recovery_area/U1/backupset/2014_03_23/o1_mf_nnndf_TAG20140323T160453_9lxy0pfb_.bkp tag=TAG20140323T160453 \nchannel ORA_DISK_1: restored backup piece 1 \nchannel ORA_DISK_1: restore complete, elapsed time: 00:00:01 \nFinished restore at 23-MAR-14\nRMAN&gt; recover tablespace demo; \nStarting recover at 23-MAR-14 \nusing channel ORA_DISK_1\nstarting media recovery \nmedia recovery complete, elapsed time: 00:00:00\nFinished recover at 23-MAR-14\nRMAN&gt; alter tablespace demo online; \nStatement processed</code></pre>\n<p>We can check the unrecoverable tablespace</p>\n<pre><code><samp></samp>RMAN&gt; report unrecoverable; \nReport of files that need backup due to unrecoverable operations \nFile Type of Backup Required Name \n---- ----------------------- ----------------------------------- \n5    full or incremental     /tmp/demo.dbf</code></pre>\n<p>but we don&#8217;t know which objects are concerned until we try to read from them:</p>\n<pre><code><samp></samp>RMAN&gt; select /*+ full(demo) */ count(*) from demo; \nRMAN-00571: =========================================================== \nRMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== \nRMAN-00571: =========================================================== \nRMAN-03002: failure of sql statement command at 03/23/2014 16:05:03 \nORA-01578: ORACLE data block corrupted (file # 5, block # 131) \nORA-01110: data file 5: '/tmp/demo.dbf' \nORA-26040: Data block was loaded using the NOLOGGING option\nRMAN&gt; select /*+ index(demo) */ count(*) from demo; \nRMAN-00571: =========================================================== \nRMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== \nRMAN-00571: =========================================================== \nRMAN-03002: failure of sql statement command at 03/23/2014 16:05:04 \nORA-01578: ORACLE data block corrupted (file # 5, block # 140) \nORA-01110: data file 5: '/tmp/demo.dbf' \nORA-26040: Data block was loaded using the NOLOGGING option</code></pre>\n<p>So I can&#8217;t read from the table because of block (file # 5, block # 131) which is corrupted and I can&#8217;t read from the index because of block (file # 5, block # 140) which is corrupted. The reason is that recovery was not possible on them as there was no redo to protect them from the time they were formatted (by the nologging operation).</p>\n<p>Let&#8217;s see which blocks were reported:</p>\n<pre><code><samp></samp>RMAN&gt; select segment_type,header_file,header_block , dbms_utility.make_data_block_address(header_file,header_block) from dba_segments where owner=user and segment_name='DEMO'; \nSEGMENT_TYPE       HEADER_FILE HEADER_BLOCK \n------------------ ----------- ------------ \nDBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(HEADER_FILE,HEADER_BLOCK) \n-------------------------------------------------------------- \nINDEX                        5          138 \n                                                      20971658\nTABLE                        5          130 \n                                                      20971650\nRMAN&gt; select dbms_utility.make_data_block_address(5, 140) from dual;\nDBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(5,140) \n------------------------------------------- \n                                   20971660</code></pre>\n<p>The full scan failed as soon as it reads the block 131 which is the first one that contains data. The segment header block itself was protected by redo.</p>\n<p>For the index the query failed on block 140 which is the first leaf (this is why I did a treedump above). The root branch (which is always the next after the segment header) seem to be protected by redo even for nologging operation. The reason why I checked that is because in the first testcase I posted in the forum, I had a very small table for which the index was so small that it had only one leaf &#8211; which is the root branch as well &#8211; so the index was still recovrable.</p>\n<p>The important point to know is that the index is still valid:</p>\n<pre><code><samp></samp>RMAN&gt; select status from all_indexes where index_name='DEMO'; \nSTATUS   \n-------- \nVALID</code></pre>\n<p>And the only solution is to truncate the table:</p>\n<pre><code><samp></samp>RMAN&gt; truncate table demo; \nStatement processed\nRMAN&gt; select /*+ full(demo) */ count(*) from demo; \n  COUNT(*) \n---------- \n         0\nRMAN&gt; select /*+ index(demo) */ count(*) from demo; \n  COUNT(*) \n---------- \n         0</code></pre>\n<p>no corruption anymore, but no data either&#8230;</p>\n<p>Last point: if you have only the indexes that are unrecoverable, you can rebuild them. But because the index is valid, Oracle will try to read it in order to rebuild it &#8211; and fail with ORA-26040. You have to make then unusable before.</p>\n<p>The core message is:</p>\n<ul>\n<li>Use nologging only when you accept to loose data and you accept to have some manual operations to do after recovery (so document it): truncate table, make indexes unusable and rebuild.</li>\n<li>Backup the unrecoverable tablespaces as soon as you can after your nologging operations</li>\n<li>If you need redo for other goals (such as standby database) use force logging.</li>\n</ul>\n",
    "protected": false
  }
}
