关于oracle数据文件拷贝

作者:八神 | 分类: 大话技术 | 标签: , | 日期:2009-02-17

前几天要备份几个standby出来,RMAN一时之间不好用,数据文件都是存裸设备的,就用起了dd,当时急于出门,
dd脚本写好后nohup上就走了,半路上才想起来standby根本没有open read only,其上的mrp进程还在做实时恢复,
FNT,晚上回家本来准备重新弄,后来感觉可以先recover,因为我dd的blocksize就是db_block_size,每个IO单元
就是一个block,而数据库写文件的最小粒度也是一个block,并且我每个block的边界也和数据库的一样,这样应
该是不存在fuzzy block的,先用dbv看了下文件,OK,然后结合日志恢复,全部OK

今天就上面的情况做了模拟,发现这么做确实是可以的

测试环境:
Oracle9i Enterprise Edition Release 9.2.0.6.0 - 64bit Production
PL/SQL Release 9.2.0.6.0 - Production
CORE    9.2.0.6.0       Production
TNS for IBM/AIX RISC System/6000: Version 9.2.0.6.0 - Production
NLSRTL Version 9.2.0.6.0 - Production

–100M的表空间
sys@testdb>create tablespace mytest datafile ‘/crmsnap/data/mytest01.dbf’ size 100M;
Tablespace created.

–测试表,大概3行一个block
sys@testdb>create table mytest(id number,txt char(2000)) tablespace mytest;
Table created.

sys@testdb>create index mytest_id_ind on mytest(id) tablespace mytest;
Index created.

sys@testdb>begin
  2  for x in 1..100000000 loop
  3     insert into mytest values(x,’wo shi ni ba hahaha’);
  4     commit;
  5  end loop;
  6  end;
  7  /
begin
*
ERROR at line 1:
ORA-01653: unable to extend table SYS.MYTEST by 1024 in tablespace MYTEST
ORA-06512: at line 3

sys@testdb>select count(*) from mytest;
  COUNT(*)
———-
     36861

开两个回话,持续执行下面SQL,这样100M的数据文件相当于被机枪扫射,轰的千疮百孔
declare v_seed pls_integer := 0;
begin
for i in 1..100000000 loop
 for x in 1..100000000 loop
         select DBMS_RANDOM.value(1,36861) into v_seed from dual ;
  update mytest set txt = ‘wo shi ni ma hahaha’ where id = v_seed;
  commit;
 end loop;
end loop;
end;
/

同时在OS上做下dd,一种是8K的blocksize,一种是512 bytes的blocksize,交替进行,整个过程中上面的SQL都在执行
dd if=/crmsnap/data/mytest01.dbf of=dd8k01.dbf bs=8192 count=12801
dd if=/crmsnap/data/mytest01.dbf of=dd512b01.dbf bs=512 count=204816
dd if=/crmsnap/data/mytest01.dbf of=dd8k02.dbf bs=8192 count=12801
dd if=/crmsnap/data/mytest01.dbf of=dd512b02.dbf bs=512 count=204816
dd if=/crmsnap/data/mytest01.dbf of=dd8k03.dbf bs=8192 count=12801
dd if=/crmsnap/data/mytest01.dbf of=dd512b03.dbf bs=512 count=204816
dd if=/crmsnap/data/mytest01.dbf of=dd8k04.dbf bs=8192 count=12801
dd if=/crmsnap/data/mytest01.dbf of=dd512b04.dbf bs=512 count=204816
dd if=/crmsnap/data/mytest01.dbf of=dd8k05.dbf bs=8192 count=12801
dd if=/crmsnap/data/mytest01.dbf of=dd512b05.dbf bs=512 count=204816

结束后,对dd的文件做dbv检查,发现所有8K BLOCK DD的文件都是好的,所有512的都有坏块
oracle@testhost:/home/oracle/chun.luoc>dbv file=dd8k04.dbf blocksize=8192
DBVERIFY: Release 9.2.0.6.0 - Production on Tue Feb 17 21:05:52 2009
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
DBVERIFY - Verification starting : FILE = dd8k04.dbf
DBVERIFY - Verification complete
Total Pages Examined         : 12800
Total Pages Processed (Data) : 12287
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 147
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 10
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 356
Total Pages Marked Corrupt   : 0
Total Pages Influx           : 0
Highest block SCN            : 6083926607980 (1416.2252916844)

oracle@testhost:/home/oracle/chun.luoc>dbv file=dd512b01.dbf blocksize=8192
DBVERIFY: Release 9.2.0.6.0 - Production on Tue Feb 17 21:03:17 2009
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
DBVERIFY - Verification starting : FILE = dd512b01.dbf
Page 2833 is influx - most likely media corrupt
***
Corrupt block relative dba: 0×0c400b11 (file 49, block 2833)
Fractured block found during dbv:
Data in bad block -
 type: 6 format: 2 rdba: 0×0c400b11
 last change scn: 0×0588.862131fe seq: 0×1 flg: 0×06
 consistency value in tail: 0xafa30601
 check value in block header: 0×8e12, computed block checksum: 0×9e5d
 spare1: 0×0, spare2: 0×0, spare3: 0×0
***

Page 8451 is influx - most likely media corrupt
***
Corrupt block relative dba: 0×0c402103 (file 49, block 8451)
Fractured block found during dbv:
Data in bad block -
 type: 6 format: 2 rdba: 0×0c402103
 last change scn: 0×0588.8622beab seq: 0×1 flg: 0×06
 consistency value in tail: 0×4f5a0601
 check value in block header: 0xce68, computed block checksum: 0xf1f1
 spare1: 0×0, spare2: 0×0, spare3: 0×0
***

DBVERIFY - Verification complete

Total Pages Examined         : 12800
Total Pages Processed (Data) : 12285
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 147
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 10
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 356
Total Pages Marked Corrupt   : 2
Total Pages Influx           : 2
Highest block SCN            : 6083924196375 (1416.2250505239)

记得去年DSG的人推荐的一个自己做的备份产品,说可以联机备份非归档模式的数据库,和他讨论了下,原理就是获取数据文件的
block size,用这个尺寸来读取文件,同时把后面在online redo里面产生的redo信息都读取记录出来,类似于人工做归档,这样
就可以恢复,道理其实和上面是一样的,当然我还是推荐使用rman,使用oracle的正规方法来做备份,上面的方法只能说是歪打误撞

回顾下这些古老的知识点,可能对大家来说都过时了
1.为什么使用os的cp命令在线的数据文件,会出现坏块?
因为cp命令拷贝文件的粒度比数据库block要小,有的只有512字节,很可能出现这种情况,cp程序拷贝了一个数据块的前面512字节,然后这个
数据块发生了变更,接着cp程序处理了block的下一个512字节,最终这个block都被cp出来了,站在数据库的角度,block的第一个512字节的数据
和第二个512字节的数据就是衔接不上的,这样就出现了坏块

2.oracle支持的begin backup,end backup + os cp可以实现联机热拷贝数据文件,这个就没有坏块吗?怎么还可以恢复?
这种模式下拷贝出来的文件照样存在坏块,叫做fuzzy block,但在下达了alter tablespace xxx begin backup命令后,oracle会将这个表空间
的数据文件特别对待,当有针对这个datafile的更改时,会先把更改的block整个装入redo中,然后是相关的undo,变更对应的日志信息生成redo,
也就是他把变更的block拷贝了一份在日志里面,当恢复的时候,ORACLE检测出数据文件的fuzzy block,他利用redo日志流里面的完整block先填充
这个fuzzy block,再应用后面的日志记录完成上边的变更重算,所以在表空间置于backup模式后,会发现日志增长的异常快,就是因为他多记录了
整个数据块

3.为什么alter tablespace xxx begin backup后需要冻结相关的数据文件头的checkpoint scn ?
使用这种模式,就意味着你准备os cp来拷贝数据文件,cp在拷贝数据文件的时候,并不保证他第一个块就是拷贝你的文件头,假如不冻结文件头SCN,
就会存在这样一种情况:CP先拷贝了数据文件的8,9,10数据块,然后前台程序更新了8,9,10数据块的数据,产生的日志流rba是10000(这部分更新
在我们拷贝的文件里面肯定看不到),接着oracle发生了checkpoint,更新了文件头的checkpoint scn,这个事件也产生了RBA,并且这个RBA肯定是>10000的,
假设是10100,然后CP拷贝了文件头,然后拷贝了文件的剩余部分,现在来恢复这个数据文件:
介质恢复的时候,oracle根据文件头的checkpoint scn找到对应的rba,从这个点开始恢复,应该是10100开始,那么他就漏掉了前面的10000-10100之间的日志,
这就是必须冻结文件头checkpoint scn的理由,而我们用的rman程序,由于他是oracle自带的,他首先拷贝的就是文件头数据块,他保证了在他生成的拷贝文件里面,
文件头的SCN对应的RBA就是恢复需要的最低RBA

5人发表了评论  ↓发表评论↓
  • 能共享下脚本吗 当然去掉你重要的数据

    yunpan @ February 18, 2009 |

  • 这样拷贝standby datafile还是可以的,但恢复的时候仍然可能会报corrupt block的错误。可能存在8k的block,写磁盘写了一半,dd却读取了整个块;不过错误出现几率较低。

    yumianfeilong @ February 18, 2009 |

  • 关于蒙牛的文章怎么删除了,我都订阅到了

    键盘人生 @ February 18, 2009 |

  • 今天和同事讨论了下,确实,ORACLE的8K IO,还有dd的8k IO,他们进入到底层,其实都是打散成更小的IO,特别是在磁盘级别,都是512字节的块,你没办法保证这些IO是完全的一致和不交替的的,上面的方法还肯定是不推荐使用的

    八神 @ February 19, 2009 |

  • 被hx了

    zy @ February 19, 2009 |

表情:<( ̄︶ ̄)> | (⊙ˍ⊙) | >﹏< | b( ̄▽ ̄)d | (─.─||) | (^_-)

[ Ctrl+Enter提交 ]

阿里巴巴DBA出品