Pythian Blog: Technical Track

RMAN full backup vs. level 0 incremental

Perhaps you've wondered about this. What is the difference between taking an RMAN full backup and a level 0 incremental backup? If you read the documentation the following explanation will be found here: Incremental Backups
The only difference between a level 0 incremental backup and a full backup is that a full backup is never included in an incremental strategy. Thus, an incremental level 0 backup is a full backup that happens to be the parent of incremental backups whose level is greater than 0.
Logically that is true, but for many folks that is not enough. Are they different physically, and if so exactly how are they different physically? If you google for an explanation you will find a number of ideas, most based on what the documentation says. Here are some examples of what I found:
  • The only difference between level 0 and full is that a level 0 is marked in the RMAN catalog as a level 0.
  • Level 0 incremental and full backups are physically identical.
If you are an experienced IT professional then by now you have learned not to assume that articles found on the WWW are always correct.It seemed like it might be an interesting exercise to find out what the differences might be. This called for some experimentation; here is the general procedure followed:
  • Put the database in mount state so there is no activity in the database.
  • Create two RMAN 'full' backups.
  • Create two RMAN incremental level 0 backups.
  • Open the database and perform some DML and/or DDL.
  • Create an incremental level 1 backup.
  • Do more DML/DDL activity.
  • Create another incremental level 1 backup.
This will provide some backup files to examine. You may be wondering why two of each backup type was made. The reason for that is to filter out changes in the backup file that are not relevant to the difference in backup types. That should become more clear with examples. The test environment is as follows:
  • Test database: Oracle 12.1.0.2 CDB on Linux 6.5.
  • RMAN Catalog database: Oracle 11.2.0.2 on Linux 5.5.
The following backup commands were used to create two full and two level 0 backups: [code language="shell"] export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS' rman target / catalog rman12c/rman12c@oravm &amp;amp;lt;&amp;amp;lt;-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/full-01/%U'; backup database tag 'full-01' plus archivelog tag 'full-01'; } EOF rman target / catalog rman12c/rman12c@oravm &amp;amp;lt;&amp;amp;lt;-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/full-02/%U'; backup database tag 'full-02' plus archivelog tag 'full-02'; } EOF rman target / catalog rman12c/rman12c@oravm &amp;amp;lt;&amp;amp;lt;-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/lvl0-01/%U'; backup incremental level 0 database tag 'lvl0-01' plus archivelog tag 'lvl0-01'; } EOF rman target / catalog rman12c/rman12c@oravm &amp;amp;lt;&amp;amp;lt;-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/lvl0-02/%U'; backup incremental level 0 database tag 'lvl0-02' plus archivelog tag 'lvl0-02'; } EOF [/code] Let's take a look at the size of the files: [code language="shell"] [root@lestrade ora12c]# ls -l full-01/* -rw-r----- 1 root root 6878208 Oct 27 15:15 full-01/0sqkp2dl_1_1 -rw-r----- 1 root root 761749504 Oct 27 15:16 full-01/0tqkp2dn_1_1 -rw-r----- 1 root root 1696112640 Oct 27 15:17 full-01/0uqkp2eq_1_1 -rw-r----- 1 root root 735043584 Oct 27 15:17 full-01/0vqkp2g7_1_1 -rw-r----- 1 root root 623837184 Oct 27 15:17 full-01/10qkp2h0_1_1 [root@lestrade ora12c]# ls -l full-02/* -rw-r----- 1 root root 6878208 Oct 27 15:18 full-02/12qkp2hm_1_1 -rw-r----- 1 root root 761749504 Oct 27 15:18 full-02/13qkp2ho_1_1 -rw-r----- 1 root root 1696112640 Oct 27 15:19 full-02/14qkp2ir_1_1 -rw-r----- 1 root root 735043584 Oct 27 15:19 full-02/15qkp2k8_1_1 -rw-r----- 1 root root 623837184 Oct 27 15:20 full-02/16qkp2l2_1_1 [root@lestrade ora12c]# ls -l lvl0-01/* -rw-r----- 1 root root 6878208 Oct 27 15:20 lvl0-01/18qkp2lm_1_1 -rw-r----- 1 root root 761749504 Oct 27 15:21 lvl0-01/19qkp2lo_1_1 -rw-r----- 1 root root 1696112640 Oct 27 15:21 lvl0-01/1aqkp2mr_1_1 -rw-r----- 1 root root 735043584 Oct 27 15:22 lvl0-01/1bqkp2o8_1_1 -rw-r----- 1 root root 623837184 Oct 27 15:22 lvl0-01/1cqkp2p2_1_1 [root@lestrade ora12c]# ls -l lvl0-02/* -rw-r----- 1 root root 6878208 Oct 27 15:23 lvl0-02/1eqkp2q4_1_1 -rw-r----- 1 root root 761749504 Oct 27 15:23 lvl0-02/1fqkp2q6_1_1 -rw-r----- 1 root root 1696112640 Oct 27 15:24 lvl0-02/1gqkp2r9_1_1 -rw-r----- 1 root root 735043584 Oct 27 15:25 lvl0-02/1hqkp2sm_1_1 -rw-r----- 1 root root 623837184 Oct 27 15:25 lvl0-02/1iqkp2tf_1_1 [/code] The number and sizes of the files appear the same regardless of the backup type, lending some credence to the idea that they may be physically identical. So now let's dump some of the files to determine the difference. For purposes of this experiment we are going to examine the backup files that contain datafile 1 from the database, the SYSTEM tablespace datafile. We can find these backup files with the RMAN list command: [code language="SQL"] RMAN> list backup of datafile 1; List of Backup Sets =================== BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ ------------------- 1259 Full 1.58G DISK 00:00:39 2015-10-27 15:15:13 BP Key: 1267 Status: AVAILABLE Compressed: NO Tag: FULL-01 Piece Name: /mnt/oracle-backups/ora12c/full-01/0uqkp2eq_1_1 List of Datafiles in backup set 1259 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- ------------------- ---- 1 Full 50957811 2015-10-27 18:08:29 +DATA/JS03/DATAFILE/system.258.856612879 BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ ------------------- 1341 Full 1.58G DISK 00:00:39 2015-10-27 15:17:22 BP Key: 1349 Status: AVAILABLE Compressed: NO Tag: FULL-02 Piece Name: /mnt/oracle-backups/ora12c/full-02/14qkp2ir_1_1 List of Datafiles in backup set 1341 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- ------------------- ---- 1 Full 50957811 2015-10-27 18:08:29 +DATA/JS03/DATAFILE/system.258.856612879 BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ ------------------- 1433 Incr 0 1.58G DISK 00:00:39 2015-10-27 15:19:30 BP Key: 1441 Status: AVAILABLE Compressed: NO Tag: LVL0-01 Piece Name: /mnt/oracle-backups/ora12c/lvl0-01/1aqkp2mr_1_1 List of Datafiles in backup set 1433 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- ------------------- ---- 1 0 Incr 50957811 2015-10-27 18:08:29 +DATA/JS03/DATAFILE/system.258.856612879 BS Key Type LV Size Device Type Elapsed Time Completion Time ------- ---- -- ---------- ----------- ------------ ------------------- 1531 Incr 0 1.58G DISK 00:00:42 2015-10-27 15:21:55 BP Key: 1539 Status: AVAILABLE Compressed: NO Tag: LVL0-02 Piece Name: /mnt/oracle-backups/ora12c/lvl0-02/1gqkp2r9_1_1 List of Datafiles in backup set 1531 File LV Type Ckp SCN Ckp Time Name ---- -- ---- ---------- ------------------- ---- 1 0 Incr 50957811 2015-10-27 18:08:29 +DATA/JS03/DATAFILE/system.258.856612879 [/code] Now dump the backup pieces to hex files. Just the first 100M is being dumped from each, resulting in ~300M text files. [code language="shell"] DUMPDIR=hexdump mkdir -p $DUMPDIR for f in full-01/0uqkp2eq_1_1 full-02/14qkp2ir_1_1 lvl0-01/1aqkp2mr_1_1 lvl0-02/1gqkp2r9_1_1 do tag=$(dirname $f) filename=$(basename $f) filename="${DUMPDIR}/${tag}_${filename}.txt" echo $filename # dump first 100M dd if=$f bs=512 count=204800 2>/dev/null | hexdump -C > $filename done [root@lestrade hexdump]# ls -l full* lvl0* -rw-r--r-- 1 root root 305807309 Oct 27 16:11 full-01_0uqkp2eq_1_1.txt -rw-r--r-- 1 root root 305807309 Oct 27 16:11 full-02_14qkp2ir_1_1.txt -rw-r--r-- 1 root root 305807309 Oct 27 16:11 lvl0-01_1aqkp2mr_1_1.txt -rw-r--r-- 1 root root 305807309 Oct 27 16:11 lvl0-02_1gqkp2r9_1_1.txt [/code] We can compare the dump of the two full backup files. As there were no changes to the database during this time (you may recall the database is in MOUNT state) the only difference in the files should be changes to metadata. [code language="shell"] [root@lestrade hexdump]# diff full-01_0uqkp2eq_1_1.txt full-02_14qkp2ir_1_1.txt 7,8c7,8 < 00002010 46 7d 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |F}...........)..| < 00002020 4a 53 30 33 00 00 00 00 de 19 01 00 00 00 00 00 |JS03............| --- > 00002010 dd 7e 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |.~...........)..| > 00002020 4a 53 30 33 00 00 00 00 fd 19 01 00 00 00 00 00 |JS03............| 12,13c12,13 < 00002060 01 00 00 00 da 89 4c 35 1e 00 00 00 04 00 00 00 |......L5........| < 00002070 01 00 00 00 46 55 4c 4c 2d 30 31 00 00 00 00 00 |....FULL-01.....| --- > 00002060 01 00 00 00 5b 8a 4c 35 24 00 00 00 04 00 00 00 |....[.L5$.......| > 00002070 01 00 00 00 46 55 4c 4c 2d 30 32 00 00 00 00 00 |....FULL-02.....| [/code] These two full backup files differ only the by these four lines. These differences are in the 17th OS block of the files and can be identified as metadata by the tags FULL-0[12] and the database name JS03. There are other differences that do not appear as printable characters. I did spend a little time trying to decode their meanings; they may be backup piece#, backup piece keys, backup set keys, and similar. Determining the meaning of these didn't really seem necessary to understand the difference between full and incremental level 0 backups, so I did not continue. If you do know what these values represent, please, leave a comment. Doing a diff on the level 0 hex dump files shows changes in the same lines: [code language="shell"] [root@lestrade hexdump]# diff lvl0-01_1aqkp2mr_1_1.txt lvl0-02_1gqkp2r9_1_1.txt 7,8c7,8 < 00002010 bc 02 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |.............)..| < 00002020 4a 53 30 33 00 00 00 00 1a 1a 01 00 00 00 00 00 |JS03............| --- > 00002010 34 03 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |4............)..| > 00002020 4a 53 30 33 00 00 00 00 39 1a 01 00 00 00 00 00 |JS03....9.......| 12,13c12,13 < 00002060 01 00 00 00 db 8a 4c 35 2a 00 00 00 04 00 00 00 |......L5*.......| < 00002070 01 00 00 00 4c 56 4c 30 2d 30 31 00 00 00 00 00 |....LVL0-01.....| --- > 00002060 01 00 00 00 69 8b 4c 35 30 00 00 00 04 00 00 00 |....i.L50.......| > 00002070 01 00 00 00 4c 56 4c 30 2d 30 32 00 00 00 00 00 |....LVL0-02.....| [/code] Now it is time to compare a full backup file to a level 0 backup file: [code language="shell"] [root@lestrade hexdump]# diff full-01_0uqkp2eq_1_1.txt lvl0-01_1aqkp2mr_1_1.txt 7,8c7,8 < 00002010 46 7d 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |F}...........)..| < 00002020 4a 53 30 33 00 00 00 00 de 19 01 00 00 00 00 00 |JS03............| --- > 00002010 bc 02 00 00 00 02 10 0c 00 02 10 0c c8 29 05 07 |.............)..| > 00002020 4a 53 30 33 00 00 00 00 1a 1a 01 00 00 00 00 00 |JS03............| 12,13c12,13 < 00002060 01 00 00 00 da 89 4c 35 1e 00 00 00 04 00 00 00 |......L5........| < 00002070 01 00 00 00 46 55 4c 4c 2d 30 31 00 00 00 00 00 |....FULL-01.....| --- > 00002060 01 00 00 00 db 8a 4c 35 2a 00 00 00 04 00 00 00 |......L5*.......| > 00002070 01 00 00 00 4c 56 4c 30 2d 30 31 00 00 00 00 00 |....LVL0-01.....| 15c15 < 00002090 00 00 00 00 04 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| --- > 00002090 00 00 00 00 05 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| [/code] Notice the new line 2090? This is the line that contains the difference between a full and a level 0 backup file. Before continuing it is time to create a couple of level 1 backups: [code language="shell"] SQL> create user dilbert identified by phb; User created. SQL> alter user dilbert quota 10m on users; User altered. SQL> create table dilbert.t1 as select systimestamp t1 from dual; Table created. ==== rman target / catalog rman12c/xxx@oravm <<-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/lvl1-01/%U'; backup incremental level 1 database tag 'lvl1-01' plus archivelog tag 'lvl1-01'; } EOF === Create another table in dilbert schema SQL> create table dilbert.t2 as select * from dba_users; Table created. rman target / catalog rman12c/xxx@oravm <<-EOF run { allocate channel ch1 device type disk format '/mnt/oracle-backups/ora12c/lvl1-03/%U'; backup incremental level 1 database tag 'lvl1-03' plus archivelog tag 'lvl1-03'; } EOF Note: lvl1-02 backup was discarded as I forgot to make db changes before making it. [/code] If we were to go on and compare all of the backup files that contain datafile 1: [code language="shell"] [root@lestrade hexdump]# grep ^00002090 *.txt full-01_0uqkp2eq_1_1.txt:00002090 00 00 00 00 04 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| full-02_14qkp2ir_1_1.txt:00002090 00 00 00 00 04 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| lvl0-01_1aqkp2mr_1_1.txt:00002090 00 00 00 00 05 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| lvl0-02_1gqkp2r9_1_1.txt:00002090 00 00 00 00 05 04 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| lvl1-01_1mqkp7jk_1_1.txt:00002090 00 00 00 00 05 00 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| lvl1-03_22qks49l_1_1.txt:00002090 00 00 00 00 05 00 00 00 5a 08 00 00 c3 2c 04 00 |........Z....,..| [/code] A bitmask emerges that is peculiar to each backup type:
Starting at offset 0x2090
  00 01 02 03 04 05 06 07
 Full 00 00 00 00 04 04 00 00 
 LVL0 00 00 00 00 05 04 00 00
 LVL1 00 00 00 00 05 00 00 00
 
What might these mean? Here's a possible explanation:
0x2094 = 0x04 = FULL
 0x2094 = 0x05 = Incremental
 
 0x2095 = 0x04 = level 0 if the previous byte is 0x05
 0x2095 = 0x00 = level 1 if the previous byte is 0x05
 
Of course this doesn't explain the purpose of 0x04 at 0x205 if the backup is 'FULL'. To fully understand these flags would require dumping and examining many more backup files, not just of datafiles but of archive logs, controlfiles, etc. One thing is clear from this experiment; there are differences in the metadata contained in the file headers when comparing a full backup to a level 0 incremental backup. It is not simply a matter of the one backup being cataloged differently by RMAN; the backup pieces can be identified as either full or incremental level backups based on the metadata in the file header. So what good is all this effort for a little bit of knowledge? How about the next time you are asked about the difference between a level 0 and full backup? Now you can say something other that quoting the documentation or some article on the internet (one that is lacking anything to backup the assertions made). If the question is posed to you during an interview, this information becomes even more valuable. Now another question comes to mind: Can backup files made with a full backup be modified to work as incremental level 0 backups? That would be an interesting experiment. This is not something one would normally do, but it is not too hard to imagine a scenario where only a full backup, an incremental level 1 backup and the following archive logs were available to recover a database. This would be a desperate measure and a last resort, but sometimes last resorts are necessary. Do you think this can be done? If so please give it a try, but only test it on an expendable test system please. Please be sure to leave a comment if you try this experiment, it would be quite interesting to discuss.   Discover more about our expertise in Oracle.

Comments (2)

Subscribe by email