为了更容易的从ASM定位与抽取Oracle数据文件,可以创建一个Perl脚本find_block.pl来自动进行处理,只需要提供数据文件名与块号。脚本find_block.pl是一个Perl脚本,它由dd或kfed命令组成。它可以与所有的Linux和Unix ASM版本与单实例的ASM或RAC环境中使用。
这个脚本必须以ASM/Grid Infrastructure用户来执行,在RAC环境中,脚本可以在任何一个节点上执行,在运行脚本之前,设置ASM环境变量并且确保ORACLE_SID,ORACLE_HOME,LD_LIBRARY_PATH等等设置正确。对于ASM 10g与11gr1来说,也可以设置环境变量PERL5LIB,比如:
export PERL5LIB=$ORACLE_HOME/perl/lib/5.8.3:$ORACLE_HOME/perl/lib/site_perl
运行脚本例子如下:
$ORACLE_HOME/perl/bin/perl find_block.pl filename block
命令中的filename是指要抽取的数据块所在文件的文件名。对于数据文件,文件名可以通过在数据库实例上执行select name from v$datafile来获得。block是要从ASM中抽取数据块的块号
输出结果类似如:
dd if=[ASM disk path] ... of=block_N.dd
或Exadata中的
kfed read dev=[ASM disk path] ... > block_N.txt
如果磁盘组是外部冗余,这个脚本将生成单个命令。对于normal冗余磁盘组文件来说,这个脚本将生成两个命令,对于high冗余磁盘组文件来说,这个脚本将生成三个命令。
下面将对于oracle 10g rac来通过find_block.pl脚来从ASM中抽取数据块
SQL> select name from v$tablespace; NAME ------------------------------ SYSTEM UNDOTBS1 SYSAUX USERS TEMP EXAMPLE UNDOTBS2 YB TEST 9 rows selected. SQL> create table t1 (name varchar2(16)) tablespace TEST; Table created. SQL> insert into t1 values ('CAT'); 1 row created. SQL> insert into t1 values ('DOG'); 1 row created. SQL> commit; Commit complete. SQL> select rowid,name from t1; ROWID NAME ------------------ ---------------- AAAN8qAAIAAAAAUAAA CAT AAAN8qAAIAAAAAUAAB DOG SQL> select dbms_rowid.rowid_block_number('AAAN8qAAIAAAAAUAAA') "block" from dual; block ---------- 20 SQL> select t.name "Tablespace", f.name "Datafile" from v$tablespace t, v$datafile f where t.ts#=f.ts# and t.name='TEST'; Tablespace Datafile ------------------------------ -------------------------------------------------- TEST +DATADG/test/datafile/test.269.930512093
切换到ASM环境,设置PERL5LIB,运行脚本
[oracle@jyrac3 bin]$ export ORACLE_SID=+ASM1 [oracle@jyrac3 bin]$ export PERL5LIB=$ORACLE_HOME/perl/lib/5.8.3:$ORACLE_HOME/perl/lib/site_perl [oracle@jyrac3 bin]$ $ORACLE_HOME/perl/bin/perl find_block.pl +DATADG/test/datafile/test.269.930512093 20 dd if=/dev/raw/raw3 bs=8192 count=1 skip=266260 of=block_20.dd dd if=/dev/raw/raw4 bs=8192 count=1 skip=266260 of=block_20.dd
从上面的输出可以看到指定的文件是normal冗余,脚本生成了两个dd命令,下面我们来运行:
[root@jyrac3 ~]# dd if=/dev/raw/raw3 bs=8192 count=1 skip=266260 of=block_20.dd 1+0 records in 1+0 records out 8192 bytes (8.2 kB) copied, 0.00608323 seconds, 1.3 MB/s
下面查看block_20.dd文件的内容,使用od工具,我们可以看到插入表中的数据:
[root@jyrac3 ~]# od -c block_20.dd | tail -3 0017740 S O R T = ' B I N A R Y ' \b , 001 0017760 001 003 D O G , 001 001 003 C A T 001 006 \r 203 0020000
可以看到DOG与CAT
Example with ASM version 12.1.0.1 in Exadata
在Exadata中,不可以使用dd命令来抽取数据块,因为磁盘对数据库服务器不可见。为了得到数据库的数据块,可以使用kfed工具,因为find_block.pl将由kfed命令组成。
$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.1.0 Production on [date] SQL> alter pluggable database BR_PDB open; Pluggable database altered. SQL> show pdbs CON_ID CON_NAME OPEN MODE RESTRICTED ------ -------- ----------- ---------- 2 PDB$SEED READ ONLY NO ... 5 BR_PDB READ WRITE NO SQL> $ sqlplus bane/welcome1@BR_PDB SQL*Plus: Release 12.1.0.1.0 Production on [date] SQL> create table TAB1 (n number, name varchar2(16)) tablespace USERS; Table created. SQL> insert into TAB1 values (1, 'CAT'); 1 row created. SQL> insert into TAB1 values (2, 'DOG'); 1 row created. SQL> commit; Commit complete. SQL> select t.name "Tablespace", f.name "Datafile" from v$tablespace t, v$datafile f where t.ts#=f.ts# and t.name='USERS'; Tablespace Datafile ---------- --------------------------------------------- USERS +DATA/CDB/054.../DATAFILE/users.588.860861901 SQL> select ROWID, NAME from TAB1; ROWID NAME ------------------ ---- AAAWYEABfAAAACDAAA CAT AAAWYEABfAAAACDAAB DOG SQL> select DBMS_ROWID.ROWID_BLOCK_NUMBER('AAAWYEABfAAAACDAAA') "Block number" from dual; Block number ------------ 131 SQL>
切换到ASM环境执行脚本
$ $ORACLE_HOME/perl/bin/perl find_block.pl +DATA/CDB/0548068A10AB14DEE053E273BB0A46D1/DATAFILE/users.588.860861901 131 kfed read dev=o/192.168.1.9/DATA_CD_03_exacelmel05 ausz=4194304 aunum=16212 blksz=8192 blknum=131 | grep -iv ^kf > block_131.txt kfed read dev=o/192.168.1.11/DATA_CD_09_exacelmel07 ausz=4194304 aunum=16267 blksz=8192 blknum=131 | grep -iv ^kf > block_131.txt
注意find_block.pl将生成两个脚本,数据文件是normal冗余,执行以下命令:
$ kfed read dev=o/192.168.1.9/DATA_CD_03_exacelmel05 ausz=4194304 aunum=16212 blksz=8192 blknum=131 | grep -iv ^kf > block_131.txt $
检查block_131文件的内容,可以看到DOG与CAT
$ more block_131.txt ... FD5106080 00000000 00000000 ... [................] Repeat 501 times FD5107FE0 00000000 00000000 ... [........,......D] FD5107FF0 012C474F 02C10202 ... [OG,......CAT..,-] $
Find any block
find_block.pl脚本可以用来从存储在ASM中的任何文件抽取数据块。执行下面的命令来抽取控制文件与随机数据块
$ $ORACLE_HOME/perl/bin/perl find_block.pl +DATA/CDB/CONTROLFILE/current.289.843047837 5 kfed read dev=o/192.168.1.9/DATA_CD_10_exacelmel05 ausz=4194304 aunum=73 blksz=16384 blknum=5 | grep -iv ^kf > block_5.txt kfed read dev=o/192.168.1.11/DATA_CD_01_exacelmel07 ausz=4194304 aunum=66 blksz=16384 blknum=5 | grep -iv ^kf > block_5.txt kfed read dev=o/192.168.1.10/DATA_CD_04_exacelmel06 ausz=4194304 aunum=78 blksz=16384 blknum=5 | grep -iv ^kf > block_5.txt $
可以看到脚本显示了正确的控制文件块大小(16K),并且生成三个不同的命令。当磁盘组data是normal冗余磁盘组时,控制文件会为high冗余(ASM中控制文件缺省为冗余)。
小结:
find_block.pl是perl脚本,它由dd或kfed命令组成用来从ASM中的文件中抽取数据块。在大多数情况下我们想要从数据文件中抽取数据块,但脚本也能从控制文件,重做日志或任何其它文件中抽取数据块。
如果文件存储在外部冗余磁盘组中,那么脚本将会生成单个命令,这可以用来从ASM磁盘中抽取数据块。
如果文件存储在normal冗余磁盘组,那么脚本将会生成两个命令,它们用来从两个不同的ASM磁盘来抽取数据块(相同副本)。
如果文件存储在high冗余磁盘组,那么脚本将会生成三个命令。