【作者简介】
本人医疗行业DBA,精通oracle底层;会文件、触发器加密的勒索恢复、asm磁盘组不能mount及各种灾难恢复,后面将利用空闲时间将自己工作中遇到的问题及整理的资料分享给更多愿意学习和提升自己的dba。作者微信号:Oray_123
【正文】
一、ASM虚拟元数据-FILE 1介绍
说明:每次从ASM中读数据时,Oracle都要先读到1号文件,从中找出要读的目标文件在磁盘上的分布位置,然后再去读取相应的文件的数据。
使用场景:asmdiskgroup 无法mount时候,需要从磁盘中找到每个asm 文件的分布信息,然后将一个个asm 文件取出来;
文件目录至关重要,市面上的恢复软件实际上都是在asm磁盘组无法mount的时候通过解析这个来抽取asm里面的不同类型的文件,然后实现的数据恢复。
file 1起点通常位于0号磁盘的2号au,但是不一定,在19c中起点可能为au 10,最好的办法是通过文件头进行定位,然后找到他的分布情况,这是最准确的。
文件目录的extent分布有两种情况,一种是小文件只有直接AU,另外一种是大文件直接+间接AU。

二、ASM虚拟元数据-FILE 1 定位
我这里以au=1M的磁盘为例,想知道虚拟元数据的分布情况,就要先找到File#1的disk number和au number的分布信息,就需要读取0号磁盘的2号AU的第一个块。或者读取文件头发现起点
读取disk header,也可以发现file directory信息位于第2个AU中。
[root@hisdb01 ~]# kfed read dev/asmdisk1|grep f1
kfdhdb.f1b1locn: 2 ; 0x0d4: 0x00000002
[grid@hisdb01 ~]$ kfed read dev/asmdisk1 aun=2 blkn=1|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 1 ; 0x004: blk=1
kfbh.block.obj: 1 ; 0x008: file=1
kfbh.check: 322659068 ; 0x00c: 0x133b62fc
kfbh.fcn.base: 0 ; 0x010: 0x00000000
kfbh.fcn.wrap: 0 ; 0x014: 0x00000000
kfbh.spare1: 0 ; 0x018: 0x00000000
kfbh.spare2: 0 ; 0x01c: 0x00000000
kfffdb.node.incarn: 1 ; 0x000: A=1 NUMM=0x0 --File incarnation information
kfffdb.node.frlist.number: 4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn: 0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes: 0 ; 0x00c: 0x00000000 --文件大小(高位),单位bytes
kfffdb.lobytes: 1048576 ; 0x010: 0x00100000 --文件大小(低位),单位bytes
kfffdb.xtntcnt: 3 ; 0x014: 0x00000003 --该文件分配的extent个数,这里是3表示该文件大小是3M;
kfffdb.xtnteof: 3 ; 0x018: 0x00000003
kfffdb.blkSize: 4096 ; 0x01c: 0x00001000 --标准asm块大小
kfffdb.flags: 1 ; 0x020: O=1 S=0 S=0 D=0 C=0 I=0 R=0 A=0 --flag标识
---flag定义如下:
O - File is original, not snapshot
S - File is striped
S - Strict allocation policy
D - File is damaged
C - File creation is committed
I - File has empty indirect block
R - File has known at-risk value
A - The at-risk value itsefl
kfffdb.fileType: 15 ; 0x021: 0x0f --15描述为ASM元数据,其中12表示数据文件,3表示redo文件
kfffdb.dXrs: 19 ; 0x022: SCHE=0x1 NUMB=0x3 --direct extent redundancy scheme
kfffdb.iXrs: 19 ; 0x023: SCHE=0x1 NUMB=0x3 --indirect extent redundancy scheme
kfffdb.dXsiz[0]: 4294967295 ; 0x024: 0xffffffff ----of direct extents of each size(目前该值表示没有冗余)
kfffdb.dXsiz[1]: 0 ; 0x028: 0x00000000
kfffdb.dXsiz[2]: 0 ; 0x02c: 0x00000000
kfffdb.iXsiz[0]: 4294967295 ; 0x030: 0xffffffff
kfffdb.iXsiz[1]: 0 ; 0x034: 0x00000000
kfffdb.iXsiz[2]: 0 ; 0x038: 0x00000000
kfffdb.xtntblk: 3 ; 0x03c: 0x0003 --Total number of dir + indir extents in this block
kfffdb.break: 60 ; 0x03e: 0x003c --Direct/indirect boundary index
kfffdb.priZn: 0 ; 0x040: KFDZN_COLD --primary extent allocation zone
kfffdb.secZn: 0 ; 0x041: KFDZN_COLD --secondary extent allocation zone(因为我这里没有冗余,所以均是0)
kfffdb.ub2spare: 0 ; 0x042: 0x0000
kfffdb.alias[0]: 4294967295 ; 0x044: 0xffffffff
kfffdb.alias[1]: 4294967295 ; 0x048: 0xffffffff
kfffdb.strpwdth: 0 ; 0x04c: 0x00 --条带宽度(也就是实际大小,比如这里是20,表示该文件实际大小是20M)
kfffdb.strpsz: 0 ; 0x04d: 0x00 --条带大小
kfffdb.usmsz: 0 ; 0x04e: 0x0000
kfffdb.crets.hi: 33097356 ; 0x050: HOUR=0xc DAYS=0x14 MNTH=0x1 YEAR=0x7e4
kfffdb.crets.lo: 1903672320 ; 0x054: USEC=0x0 MSEC=0x1ef SECS=0x17 MINS=0x1c --文件创建时间(高低位组合换算集合起来即可)
kfffdb.modts.hi: 33097356 ; 0x058: HOUR=0xc DAYS=0x14 MNTH=0x1 YEAR=0x7e4
kfffdb.modts.lo: 1903672320 ; 0x05c: USEC=0x0 MSEC=0x1ef SECS=0x17 MINS=0x1c --文件修改时间(高低位组合换算集合起来即可)
kfffdb.dasz[0]: 0 ; 0x060: 0x00
kfffdb.dasz[1]: 0 ; 0x061: 0x00
kfffdb.dasz[2]: 0 ; 0x062: 0x00
kfffdb.dasz[3]: 0 ; 0x063: 0x00
kfffdb.permissn: 0 ; 0x064: 0x00
kfffdb.ub1spar1: 0 ; 0x065: 0x00
kfffdb.ub2spar2: 0 ; 0x066: 0x0000
kfffdb.user.entnum: 0 ; 0x068: 0x0000
kfffdb.user.entinc: 0 ; 0x06a: 0x0000
kfffdb.group.entnum: 0 ; 0x06c: 0x0000
kfffdb.group.entinc: 0 ; 0x06e: 0x0000
kfffdb.spare[0]: 0 ; 0x070: 0x00000000
...
kfffdb.spare[11]: 0 ; 0x09c: 0x00000000
kfffdb.usm: ; 0x0a0: length=0
kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002 --第1个au指针
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000 --该au所在的disk编号
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0 --标志位
kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28 --校验码
kfffde[1].xptr.au: 2 ; 0x4a8: 0x00000002 --第2个au指针
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001 --该au所在的disk编号
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 41 ; 0x4af: 0x29
kfffde[2].xptr.au: 2 ; 0x4b0: 0x00000002 --第3个au指针
kfffde[2].xptr.disk: 2 ; 0x4b4: 0x0002 --该au所在的disk编号
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 42 ; 0x4b7: 0x2a
kfffde[4].xptr.au: 4294967295 ; 0x4c0: 0xffffffff --表示后面没有au指针
kfffde[4].xptr.disk: 65535 ; 0x4c4: 0xffff
kfffde[4].xptr.flags: 0 ; 0x4c6: L=0 E=0 D=0 S=0
kfffde[4].xptr.chk: 42 ; 0x4c7: 0x2a
...
从上面数据可以看出,file directory元数据结构分为3部分:
1) kfbh,头部信息,这部分信息通用;
2)kfffdb,主要包括文件分配信息;
3)kffde,主要是数据文件所分配的au的具体信息;
到这里,基本上file directory的结构信息,我们描述的比较清楚了,大家可以发现,这其实非常简单。那么,到最后自然也就出现了一个问题,比如我这里的某个datafile,存于asm中,我怎么知道它所占据的au位置呢?具体在asm diskgroup中的什么地方呢?在这里,我用一个datafile来进行展示:
三、ASM 元数据查询
我这里以au=1M的磁盘为例,想知道虚拟元数据的分布情况,就要先找到File#1的disk number和au number的分布信息,就需要读取0号磁盘的2号AU的第一个块。
读取disk header,也可以发现file directory信息位于第2个AU中。
[root@hisdb01 ~]# kfed read dev/asmdata1|grep f1
kfdhdb.f1b1locn: 2 ; 0x0d4: 0x00000002
set line 220
col name for a10
col state for a10
col COMPATIBILITY for a15
col database_compatibility for a15
select group_number,name,state,type,total_mb/1024 totol_gb,free_mb/1024 as free_gb,usable_file_mb/1024 usable_file_gb,allocation_unit_size/1024/1024 unit_mb,offline_disks,compatibility,database_compatibility,voting_files from v$asm_diskgroup order by 1;
GROUP_NUMBER NAME STATE TYPE TOTOL_GB FREE_GB USABLE_FILE_GB UNIT_MB OFFLINE_DISKS COMPATIBILITY DATABASE_COMPAT VO
------------ ---------- ---------- ------------ ---------- ---------- -------------- ---------- ------------- --------------- --------------- --
1 DATA MOUNTED EXTERN 5.859375 3.98144531 3.98144531 1 0 11.2.0.0.0 10.1.0.0.0 N
2 FRA MOUNTED EXTERN 39.0625 35.5048828 35.5048828 1 0 11.2.0.0.0 11.2.0.0.0 N
3 OCR MOUNTED NORMAL 2.9296875 1.78515625 .404296875 4 0 11.2.0.0.0 10.1.0.0.0 Y
set line 250 pages 222
col dno for a5
col name for a13
col state for a10
col path for a20
col FAILGROUP for a13
col header_status for a15
col rpt for 99999
select group_number||'_'||disk_number as dno,name,failgroup,failgroup_type,path,create_date,mount_date,mount_status,header_status,state,os_mb,total_mb,free_mb,voting_file,repair_timer rpt from v$asm_disk order by 1;
DNO NAME FAILGROUP FAILGROUP_TYPE PATH CREATE_DATE MOUNT_DATE MOUNT_STATUS HEADER_STATUS STATE OS_MB TOTAL_MB FREE_MB VO RPT
----- ------------- ------------- -------------- -------------------- ------------------- ------------------- -------------- --------------- ---------- ---------- ---------- ---------- -- ------
1_0 DATA_0000 DATA_0000 REGULAR dev/asmdata1 2023-02-01 16:41:33 2023-02-01 16:41:43 CACHED MEMBER NORMAL 3000 3000 2038 N 0
1_1 DATA_0001 DATA_0001 REGULAR dev/asmdata2 2023-02-01 16:41:33 2023-02-01 16:41:43 CACHED MEMBER NORMAL 3000 3000 2039 N 0
2_0 FRA_0000 FRA_0000 REGULAR dev/asmdisk6 2020-01-20 12:50:03 2023-02-01 16:43:05 CACHED MEMBER NORMAL 10000 10000 9086 N 0
2_1 FRA_0001 FRA_0001 REGULAR dev/asmdisk4 2022-10-17 17:09:03 2023-02-01 16:43:05 CACHED MEMBER NORMAL 30000 30000 27271 N 0
3_0 OCR_0000 OCR_0000 REGULAR dev/asmdisk1 2022-10-18 11:26:03 2023-01-31 14:04:37 CACHED MEMBER NORMAL 1000 1000 608 Y 0
3_1 OCR_0001 OCR_0001 REGULAR dev/asmdisk2 2022-10-18 11:26:03 2023-01-31 14:04:37 CACHED MEMBER NORMAL 1000 1000 608 Y 0
3_2 OCR_0002 OCR_0002 REGULAR dev/asmdisk3 2022-10-18 11:26:03 2023-01-31 14:04:37 CACHED MEMBER NORMAL 1000 1000 612 Y 0
15 rows selected.
3.1 案例1-查找File#1的AU分布情况:
kfed read dev/asmdata1 aun=2 blkn=1|grep disk|grep -v 65535
kfed read dev/asmdata1 aun=2 blkn=1|grep au|grep -v 4294967295
kfed read dev/asmdata1 aun=2 blkn=1 aus=1048576|egrep "disk|au"|egrep -v "65535|4294967295"
[root@hisdb01 ~]# kfed read dev/asmdata1 aun=2 blkn=1 aus=1048576|egrep "disk|au"|egrep -v "65535|4294967295"
kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000
kfffde[1].xptr.au: 72 ; 0x4a8: 0x00000048
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
--我们这里看到有两个au:
disk 0 ,au 2 (从块1-255保存的是file1-file255元文件区的分配信息)
disk 1 ,au 72 (从块256-512保存的是file256-file512 数据库文件区的分配信息)
[root@hisdb01 ~]# kfed read dev/asmdata1 aun=2 blkn=1 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 1 ; 0x004: blk=1
kfbh.block.obj: 1 ; 0x008: file=1
kfbh.check: 2767617004 ; 0x00c: 0xa4f67bec
kfbh.fcn.base: 6491 ; 0x010: 0x0000195b
kfbh.fcn.wrap: 0 ; 0x014: 0x00000000
...
Kfed可以帮我们列出很多信息,有了这些,ASM的大部分秘密将被揭开。kfed的信息是这样看的,比如:
kfbh.endian: 1 ; 0x000: 0x01
kfbh.endian是C语言的结构(struct)中的域。
1 ; 0x000: 0x01 :kfbh.endian的十进值为1,0x000是指它开始自第0个字节处,最后的0x01是十六进制值形式。
此域的意义是主机的大小端。0是大端,1是小端。此处值为1,说明主机是小端。
其他的这里就不再一一列出了,对其中的每个域,我后面有详细的说明。下面,只说相关的,在Kfed中找到如下信息:
kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002 --kfffde[0]的数据元素,存放了1号文件第一个AU的位置。kfffde[1]存放了1号文件第二个AU位置,等等,依次类推。
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000 --0号磁盘 2号au
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0 --标志位
kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28 --校验码
kfffde[1].xptr.au: 72 ; 0x4a8: 0x00000048 --1号磁盘,72号AU
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 99 ; 0x4af: 0x63
kfffde[2].xptr.au: 4294967295 ; 0x4b0: 0xffffffff
kfffde[2].xptr.disk: 65535 ; 0x4b4: 0xffff
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 42 ; 0x4b7: 0x2a
kfffde[3].xptr.au: 4294967295 ; 0x4b8: 0xffffffff
kfffde[3].xptr.disk: 65535 ; 0x4bc: 0xffff
kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 S=0
kfffde[3].xptr.chk: 42 ; 0x4bf: 0x2a
通过上面kfffde[0]中的信息,我们可以知道,1号文件的第一个AU,位置在0号盘2号AU处。
再看kfffde[1],它对应1号文件第二个AU,位置在1号盘72号AU。
再往下看kfffde[2],AU编号4294967295,磁盘编号65535。这说明1号文件还没有第三个AU。
通过上面的信息,我们可以得到,1号文件共有两个AU,分别在0号盘2号AU、1号盘72号AU。
3.2 案例2-查找File#3的AU分布情况:
再来一个例子,假设我们想要访问3号文件,如何找出3号文件的AU都在哪里分布呢?
根据我们刚才所讲的,3号文件的AU分布,在(0号盘,2号AU,3号块)中,使用Kfed读取它:
[root@hisdb01 ~]# kfed read dev/asmdata1 aun=2 blkn=3 aus=1048576|more
...
kfffde[0].xptr.au: 4 ; 0x4a0: 0x00000004
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk: 46 ; 0x4a7: 0x2e
kfffde[1].xptr.au: 2 ; 0x4a8: 0x00000002
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 41 ; 0x4af: 0x29
kfffde[2].xptr.au: 5 ; 0x4b0: 0x00000005
kfffde[2].xptr.disk: 0 ; 0x4b4: 0x0000
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 47 ; 0x4b7: 0x2f
kfffde[3].xptr.au: 3 ; 0x4b8: 0x00000003
kfffde[3].xptr.disk: 1 ; 0x4bc: 0x0001
kfffde[3].xptr.flags: 0 ; 0x4be: L=0 E=0 D=0 S=0
kfffde[3].xptr.chk: 40 ; 0x4bf: 0x28
...
根据我们前面我讲的,解读这些信息是很容易的。3号文件的AU有:(0号盘4号AU)、(1号盘2号AU)、(0号盘5号AU)、(1号盘3号AU)、…………。
3.3 案例3-查找控制文件的AU分布情况:
col type for a12
select group_number,file_number,bytes,type from v$asm_file where type='CONTROLFILE';
select name from v$controlfile;
GROUP_NUMBER FILE_NUMBER BYTES TYPE
------------ ----------- ---------- ------------
2 256 18497536 CONTROLFILE
1 260 18497536 CONTROLFILE
这里控制文件有两个,一个在磁盘组FRA,一个在DATA,我这里读取的是group_number为1的DATA磁盘组;
接下来我们读取FILE#260的文件分布,就需要到FILE #1 的第二个AU块里面去找,--DATA磁盘组的1号磁盘,72号AU,第(260-255)-1 = 4个块里面去找;
为什么是第4号块? 因为2号AU是从块0~256来记录文件的,无需预留;(默认从0号块开始,所以第四个块代表了260号文件)
[root@hisdb01 ~]# kfed read dev/asmdata2 aun=72 blkn=4 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 260 ; 0x004: blk=260 --这里可以看到就是260号块,对应的文件就是ctl
kfbh.block.obj: 1 ; 0x008: file=1
...
[root@hisdb01 ~]# kfed read dev/asmdata2 aun=72 blkn=4 aus=1048576|egrep "disk|au"|egrep -v "65535|4294967295"
kfffde[0].xptr.au: 695 ; 0x4a0: 0x000002b7
kfffde[0].xptr.disk: 1 ; 0x4a4: 0x0001
kfffde[1].xptr.au: 697 ; 0x4a8: 0x000002b9
kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000
kfffde[2].xptr.au: 696 ; 0x4b0: 0x000002b8
kfffde[2].xptr.disk: 1 ; 0x4b4: 0x0001
kfffde[3].xptr.au: 698 ; 0x4b8: 0x000002ba
kfffde[3].xptr.disk: 0 ; 0x4bc: 0x0000
kfffde[4].xptr.au: 697 ; 0x4c0: 0x000002b9
kfffde[4].xptr.disk: 1 ; 0x4c4: 0x0001
kfffde[5].xptr.au: 699 ; 0x4c8: 0x000002bb
kfffde[5].xptr.disk: 0 ; 0x4cc: 0x0000
kfffde[6].xptr.au: 698 ; 0x4d0: 0x000002ba
kfffde[6].xptr.disk: 1 ; 0x4d4: 0x0001
kfffde[7].xptr.au: 700 ; 0x4d8: 0x000002bc
kfffde[7].xptr.disk: 0 ; 0x4dc: 0x0000
kfffde[8].xptr.au: 699 ; 0x4e0: 0x000002bb
kfffde[8].xptr.disk: 1 ; 0x4e4: 0x0001
kfffde[9].xptr.au: 701 ; 0x4e8: 0x000002bd
kfffde[9].xptr.disk: 0 ; 0x4ec: 0x0000
kfffde[10].xptr.au: 700 ; 0x4f0: 0x000002bc
kfffde[10].xptr.disk: 1 ; 0x4f4: 0x0001
kfffde[11].xptr.au: 702 ; 0x4f8: 0x000002be
kfffde[11].xptr.disk: 0 ; 0x4fc: 0x0000
kfffde[12].xptr.au: 701 ; 0x500: 0x000002bd
kfffde[12].xptr.disk: 1 ; 0x504: 0x0001
kfffde[13].xptr.au: 703 ; 0x508: 0x000002bf
kfffde[13].xptr.disk: 0 ; 0x50c: 0x0000
kfffde[14].xptr.au: 702 ; 0x510: 0x000002be
kfffde[14].xptr.disk: 1 ; 0x514: 0x0001
kfffde[15].xptr.au: 704 ; 0x518: 0x000002c0
kfffde[15].xptr.disk: 0 ; 0x51c: 0x0000
kfffde[16].xptr.au: 703 ; 0x520: 0x000002bf
kfffde[16].xptr.disk: 1 ; 0x524: 0x0001
kfffde[17].xptr.au: 705 ; 0x528: 0x000002c1
kfffde[17].xptr.disk: 0 ; 0x52c: 0x0000
kfffde[18].xptr.au: 704 ; 0x530: 0x000002c0
kfffde[18].xptr.disk: 1 ; 0x534: 0x0001
kfffde[19].xptr.au: 706 ; 0x538: 0x000002c2
kfffde[19].xptr.disk: 0 ; 0x53c: 0x0000
kfffde[20].xptr.au: 705 ; 0x540: 0x000002c1
kfffde[20].xptr.disk: 1 ; 0x544: 0x0001
kfffde[21].xptr.au: 707 ; 0x548: 0x000002c3
kfffde[21].xptr.disk: 0 ; 0x54c: 0x0000
kfffde[22].xptr.au: 706 ; 0x550: 0x000002c2
kfffde[22].xptr.disk: 1 ; 0x554: 0x0001
kfffde[23].xptr.au: 708 ; 0x558: 0x000002c4
kfffde[23].xptr.disk: 0 ; 0x55c: 0x0000
最后我们找一个AU来确认一下是否是控制文件。我们用操作系统的dd命令读取1号磁盘的第698号AU信息。
1_0 DATA_0000 DATA_0000 REGULAR dev/asmdata1
1_1 DATA_0001 DATA_0001 REGULAR dev/asmdata2
[root@hisdb01 ~]# dd if=/dev/asmdata2 bs=1M count=1 skip=698|strings
+DATA/orcl/onlinelog/group_2.262.1127667115
+FRA/orcl/onlinelog/group_2.290.1127667117
+DATA/orcl/onlinelog/group_1.261.1127667113
+FRA/orcl/onlinelog/group_1.421.1127667115
+DATA/orcl/datafile/users.259.1127666971
+DATA/orcl/datafile/undotbs1.258.1127666971
+DATA/orcl/datafile/sysaux.257.1127666971
+DATA/orcl/datafile/system.256.1127666969
+DATA/orcl/tempfile/temp.263.1127667121
+DATA/orcl/datafile/undotbs2.264.1127667199
+DATA/orcl/datafile/undotbs3.265.1127667201
+DATA/orcl/onlinelog/group_5.266.1127667399
+FRA/orcl/onlinelog/group_5.330.1127667401
+DATA/orcl/onlinelog/group_6.267.1127667401
...
通过视图X$KFFXP可以更直观地查看ASM file的物理分配AU情况。该视图主要是反映了File Extent Map的映射关系。ASM把文件分成多个Extent,而Extent是由AU构成的。
通过X$KFFXP和v$asm_alias、v$asm_disk、v$asm_diskgroup等相连,可以方便地查询到各个ASM File的AU分布情况:
--database instance
SQL> select name from v$controlfile;
NAME
--------------------------------------------------------------------------------
+DATA/orcl/controlfile/current.260.1127667109
+FRA/orcl/controlfile/current.256.1127667111
--asm instance
set line 300 pagesize 1000
col name for a24
col type for a7
col extent for 99999
col path for a15
col failgrp for a10
col grp# for 999
col disk# for 9999
col file# for 9999
col au# for 999999
col au_size for 9999999
select a.file_number as file#,a.name,x.xnum_kffxp as extent,a.group_number as grp#,d.disk_number as disk#,
au_kffxp as au#,dg.allocation_unit_size as au_size,
decode(x.lxn_kffxp,0,'PRIMARY',1,'MIRROR') AS type,d.failgroup as failgrp,d.path
from v$asm_alias a,x$kffxp x,v$asm_disk d,v$asm_diskgroup dg
where lower(a.name)='current.260.1127667109'
and x.group_kffxp=a.group_number
and x.group_kffxp=dg.group_number
and x.group_kffxp=d.group_number
and x.number_kffxp=a.file_number
and x.disk_kffxp=d.disk_number
order by x.xnum_kffxp;
FILE# NAME EXTENT GRP# DISK# AU# AU_SIZE TYPE FAILGRP PATH
----- ------------------------ ------ ---- ----- ------- -------- ------- ---------- ---------------
260 Current.260.1127667109 0 1 1 695 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 1 1 0 697 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 2 1 1 696 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 3 1 0 698 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 4 1 1 697 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 5 1 0 699 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 6 1 1 698 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 7 1 0 700 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 8 1 1 699 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 9 1 0 701 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 10 1 1 700 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 11 1 0 702 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 12 1 1 701 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 13 1 0 703 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 14 1 1 702 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 15 1 0 704 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 16 1 1 703 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 17 1 0 705 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 18 1 1 704 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 19 1 0 706 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 20 1 1 705 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 21 1 0 707 1048576 PRIMARY DATA_0000 dev/asmdata1
260 Current.260.1127667109 D 1 1 706 1048576 PRIMARY DATA_0001 dev/asmdata2
260 Current.260.1127667109 23 1 0 708 1048576 PRIMARY DATA_0000 dev/asmdata1
24 rows selected.
3.4 案例4-读取数据文件(直接AU)
我先在asm中新建一个数据文件,然后,我们再来查看它的分布:
创建如下表空间:
--db instance
create tablespace test datafile '+data/orcl/datafile/test.dbf' size 10M autoextend off;
create table t1 tablespace test as select object_id,object_name from dba_objects where rownum<=100;
create table t2 tablespace test as select object_id,object_name from dba_objects where rownum<=100;
SQL> select name from v$datafile;
NAME
---------------------------------------
...
+DATA/orcl/datafile/test.dbf
--asm instance
SQL> col name for a20
SQL> select name,file_number from v$asm_alias where name like '%test%';
NAME FILE_NUMBER
-------------------- -----------
test.dbf 271
FILE_NUMBER也是文件号,我们一般称它为文件索引号,在这里test.dbf的索引号为271
1号文件的第一个au(0号盘的2号AU)中,只能保存1~255号文件所对应的AU分布,从256号文件开始,AU的分布信息保存在1号文件的第二个au中,也就是(1号磁盘的72号AU中),如下命令查询:
[root@hisdb01 ~]# kfed read dev/asmdata1 aun=2 blkn=1 aus=1048576|egrep "kfbh.block.blk|disk|au"|egrep -v "65535|4294967295"
kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000
kfffde[1].xptr.au: 72 ; 0x4a8: 0x00000048
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
--DATA磁盘组的1号磁盘,72号AU,第(271-255)-1 = 15个块里面去找;
为什么是第15号块? 因为2号AU是从块0~256来记录文件的,无需预留;(默认从0号块开始,所以第15个块代表了271号文件)
[root@hisdb01 ~]# kfed read /dev/asmdata2 aun=72 blkn=15 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 271 ; 0x004: blk=271
kfbh.block.obj: 1 ; 0x008: file=1
[root@hisdb01 ~]# kfed read /dev/asmdata2 aun=72 blkn=15 aus=1048576|egrep "disk|au"|egrep -v "65535|4294967295"
kfffde[0].xptr.au: 1006 ; 0x4a0: 0x000003ee
kfffde[0].xptr.disk: 1 ; 0x4a4: 0x0001
kfffde[1].xptr.au: 1007 ; 0x4a8: 0x000003ef
kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000
kfffde[2].xptr.au: 1007 ; 0x4b0: 0x000003ef
kfffde[2].xptr.disk: 1 ; 0x4b4: 0x0001
kfffde[3].xptr.au: 1008 ; 0x4b8: 0x000003f0
kfffde[3].xptr.disk: 0 ; 0x4bc: 0x0000
kfffde[4].xptr.au: 1008 ; 0x4c0: 0x000003f0
kfffde[4].xptr.disk: 1 ; 0x4c4: 0x0001
kfffde[5].xptr.au: 1009 ; 0x4c8: 0x000003f1
kfffde[5].xptr.disk: 0 ; 0x4cc: 0x0000
kfffde[6].xptr.au: 1009 ; 0x4d0: 0x000003f1
kfffde[6].xptr.disk: 1 ; 0x4d4: 0x0001
kfffde[7].xptr.au: 1010 ; 0x4d8: 0x000003f2
kfffde[7].xptr.disk: 0 ; 0x4dc: 0x0000
kfffde[8].xptr.au: 1010 ; 0x4e0: 0x000003f2
kfffde[8].xptr.disk: 1 ; 0x4e4: 0x0001
kfffde[9].xptr.au: 1011 ; 0x4e8: 0x000003f3
kfffde[9].xptr.disk: 0 ; 0x4ec: 0x0000
kfffde[10].xptr.au: 1011 ; 0x4f0: 0x000003f3
kfffde[10].xptr.disk: 1 ; 0x4f4: 0x0001
kfffde[11].xptr.au: 4294967295 ; 0x4f8: 0xffffffff
kfffde[11].xptr.disk: 65535 ; 0x4fc: 0xffff
271号文件一共10个AU,所以,kfffde[11]中的AU位置和磁盘位置是0xffffffff、0xffff。但kfffde[10]还有是明确的值的。271号文件的10号AU位置:1号磁盘1011号AU,这其实是271的第11个AU。
test表空间使用的是“系统管理区大小”,也就是说区大小有64K、1M、8M等多种选择。但是无论区大小,每个ASM中的文件,比原大小总会多出一个AU。就像这里的271号文件,原大小是10M,但实际是11M,共11个AU。
梳理一下读取271号数据文件的步骤:
1) 找1号文件(文件目录),读取disk 0 au 2
2) 读取1号块
3) 找到1号文件的第二个AU的位置,即kfffde[1],disk 1 au 72;
4) 读取disk 1 au 72(此块是保存文件256之后的分布信息)
5) 根据(271-255)-1 = 15个块获取 271号文件的AU分配信息
6) 271号文件第一个au位置是(DISK 1,AU 1006),第二个au位置是(DISK 0,AU 1007),一直读到kfffde[10] au位置是(DISK 0,AU 1007)
--asm instance
set line 300 pagesize 1000
col name for a24
col type for a7
col extent for 99999
col path for a15
col failgrp for a10
col grp# for 999
col disk# for 9999
col file# for 9999
col au# for 999999
col au_size for 9999999
select a.file_number as file#,a.name,x.xnum_kffxp as extent,a.group_number as grp#,d.disk_number as disk#,
au_kffxp as au#,dg.allocation_unit_size as au_size,
decode(x.lxn_kffxp,0,'PRIMARY',1,'MIRROR') AS type,d.failgroup as failgrp,d.path,
--'dd if='||path||' bs='||allocation_unit_size/1024||'k count=1 skip='||au_kffxp||' of=/tmp/test_1.dbf' as ou_t,
--'dd if=/tmp/test_1.dbf of=/tmp/test.dbf bs=1024k count=1 seek=0' as ou_i
'dd if='||path||' bs='||allocation_unit_size/1024||'k count=1 skip='||au_kffxp||' seek='||x.xnum_kffxp||' of=/tmp/'|| a.name
from v$asm_alias a,x$kffxp x,v$asm_disk d,v$asm_diskgroup dg
where lower(a.name)='test.dbf'
and x.group_kffxp=a.group_number
and x.group_kffxp=dg.group_number
and x.group_kffxp=d.group_number
and x.number_kffxp=a.file_number
and x.disk_kffxp=d.disk_number
order by x.xnum_kffxp;
dd if=/dev/asmdata2 bs=1024k count=1 skip=1006 seek=0 of=/tmp/test.dbf
dd if=/dev/asmdata1 bs=1024k count=1 skip=1007 seek=1 of=/tmp/test.dbf
dd if=/dev/asmdata2 bs=1024k count=1 skip=1007 seek=2 of=/tmp/test.dbf
dd if=/dev/asmdata1 bs=1024k count=1 skip=1008 seek=3 of=/tmp/test.dbf
…………类此处理…………
dd if=/dev/asmdata2 bs=1024k count=1 skip=1010 seek=8 of=/tmp/test.dbf
dd if=/dev/asmdata1 bs=1024k count=1 skip=1011 seek=9 of=/tmp/test.dbf
dd if=/dev/asmdata2 bs=1024k count=1 skip=1011 seek=10 of=/tmp/test.dbf
[root@hisdb01 tmp]# chown oracle:oinstall test.dbf
--dbv 验证
[oracle@hisdb01 tmp]$ dbv file=test.dbf blocksize=8192
DBVERIFY: Release 11.2.0.4.0 - Production on Thu Feb 2 16:16:13 2023
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
DBVERIFY - Verification starting : FILE = /tmp/test.dbf
DBVERIFY - Verification complete
Total Pages Examined : 1280
Total Pages Processed (Data) : 2
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 133
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 1145
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 1171418 (0.1171418)
[oracle@hisdb01 tmp]$ dbv file="+DATA/orcl/datafile/test.dbf" userid=sys/oracle blocksize=8192
DBVERIFY: Release 11.2.0.4.0 - Production on Thu Feb 2 16:16:19 2023
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
DBVERIFY - Verification starting : FILE = +DATA/orcl/datafile/test.dbf
DBVERIFY - Verification complete
Total Pages Examined : 1280
Total Pages Processed (Data) : 2
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 0
Total Pages Failing (Index): 0
Total Pages Processed (Other): 133
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 1145
Total Pages Marked Corrupt : 0
Total Pages Influx : 0
Total Pages Encrypted : 0
Highest block SCN : 0 (0.0)
--数据库验证文件
SQL> select name from v$datafile;
NAME
--------------------------------------------------------------------------------
+DATA/orcl/datafile/system.256.1127666969
+DATA/orcl/datafile/sysaux.257.1127666971
+DATA/orcl/datafile/undotbs1.258.1127666971
+DATA/orcl/datafile/users.259.1127666971
+DATA/orcl/datafile/undotbs2.264.1127667199
+DATA/orcl/datafile/undotbs3.265.1127667201
+DATA/orcl/datafile/test.dbf
7 rows selected.
SQL> alter database datafile '+DATA/orcl/datafile/test.dbf' offline;
Database altered.
SQL> alter database rename file '+DATA/orcl/datafile/test.dbf' to '/tmp/test.dbf';
Database altered.
SQL> recover datafile '/tmp/test.dbf';
Media recovery complete.
SQL> alter database datafile '/tmp/test.dbf' online;
Database altered.
SQL> select count(*) from t1;
COUNT(*)
----------
100
SQL> select count(*) from t2;
COUNT(*)
----------
100
3.5 案例5-读取数据文件(直接AU+间接AU)
创建一个稍大一点的数据文件,比如200M:
create tablespace test1 datafile '+DATA/orcl/datafile/test02.dbf' size 200M autoextend off;
根据我们前面所讲的,每个ASM中的文件,比原大小总会多出一个AU,200M的数据文件,在ASM中实际将占用201M空间(201个AU)。下面,我们查找一下此文件的AU分布。首先在ASM中执行如下命令:
col name for a40
col file_number for 999999999
select name,file_number from v$asm_alias where name like 'test%';
NAME FILE_NUMBER
---------------------------------------- -----------
test02.dbf 272
确定一下,test02.dbf的文件号是272。它的AU分布信息,应该在1号文件的第二个AU的第16个块中,老规距,先用Kfed读取1号文件第二个AU第16个块,也就是1号盘、72号AU、16号块:
select 272 -255-1 from dual;
[root@hisdb01 ~]# kfed read /dev/asmdata2 aun=72 blkn=16 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 272 ; 0x004: blk=272
………………………………………………………………
kfffde[0].xptr.au: 1017 ; 0x4a0: 0x000003f9
kfffde[0].xptr.disk: 1 ; 0x4a4: 0x0001
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk: 209 ; 0x4a7: 0xd1
kfffde[1].xptr.au: 1017 ; 0x4a8: 0x000003f9
kfffde[1].xptr.disk: 0 ; 0x4ac: 0x0000
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 208 ; 0x4af: 0xd0
………………………………………………………………
这些结构都比较熟悉了,是说明272号文件的分布,第一个au在1号磁盘1017 au,第二个au在0号磁盘1017 au。等等,一直往下翻页,你会发现在kfffde[61]处,au信息和disk信息已经没有了。kffde[60]是最后一个有效au,位置是0号磁盘1047 au。
………………………………………………………………
kfffde[59].xptr.au: 1046 ; 0x678: 0x00000416
kfffde[59].xptr.disk: 0 ; 0x67c: 0x0000
kfffde[59].xptr.flags: 0 ; 0x67e: L=0 E=0 D=0 S=0
kfffde[59].xptr.chk: 56 ; 0x67f: 0x38
kfffde[60].xptr.au: 1047 ; 0x680: 0x00000417 --间接AU
kfffde[60].xptr.disk: 0 ; 0x684: 0x0000
kfffde[60].xptr.flags: 0 ; 0x686: L=0 E=0 D=0 S=0
kfffde[60].xptr.chk: 57 ; 0x687: 0x39
kfffde[61].xptr.au: 4294967295 ; 0x688: 0xffffffff
kfffde[61].xptr.disk: 65535 ; 0x68c: 0xffff
kfffde[61].xptr.flags: 0 ; 0x68e: L=0 E=0 D=0 S=0
kfffde[61].xptr.chk: 42 ; 0x68f: 0x2a
………………………………………………………………
其实,kfffde[60]已经不是272号文件实际存放数据的AU了,直到kffde[59]还是,也就是说kffde[0]到kffde[59],是272号文件的前60个au的位置信息(也就是前60M),保存在此处。由于272号文件有201个AU,那么后141个au的位置信息存放在哪里呢?就在kfffde[60]对应的0号磁盘1047AU上;
再来读取0号磁盘的1047AU: --间接AU
[root@hisdb01 ~]# kfed read /dev/asmdata1 aun=1047 blkn=0 aus=1048576|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 12 ; 0x002: KFBTYP_INDIRECT
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 2147483648 ; 0x004: blk=0 (indirect)
kfbh.block.obj: 272 ; 0x008: file=272
………………………………………………………………
kfbh.block.obj,它代表此数据块属于哪个文件,此处是272,代表此数据块、此AU属于272号文件。
kffixe[0].xptr.au: 1047 ; 0x00c: 0x00000417 --61号AU
kffixe[0].xptr.disk: 1 ; 0x010: 0x0001
kffixe[0].xptr.flags: 0 ; 0x012: L=0 E=0 D=0 S=0
kffixe[0].xptr.chk: 56 ; 0x013: 0x38
kffixe[1].xptr.au: 1048 ; 0x014: 0x00000418 --62号AU
kffixe[1].xptr.disk: 0 ; 0x018: 0x0000
kffixe[1].xptr.flags: 0 ; 0x01a: L=0 E=0 D=0 S=0
kffixe[1].xptr.chk: 54 ; 0x01b: 0x36
kffixe[2].xptr.au: 1048 ; 0x01c: 0x00000418 --63号AU
kffixe[2].xptr.disk: 1 ; 0x020: 0x0001
kffixe[2].xptr.flags: 0 ; 0x022: L=0 E=0 D=0 S=0
kffixe[2].xptr.chk: 55 ; 0x023: 0x37
...
kffixe[139].xptr.au: 1117 ; 0x464: 0x0000045d --140号AU
kffixe[139].xptr.disk: 0 ; 0x468: 0x0000
kffixe[139].xptr.flags: 0 ; 0x46a: L=0 E=0 D=0 S=0
kffixe[139].xptr.chk: 115 ; 0x46b: 0x73
kffixe[140].xptr.au: 1117 ; 0x46c: 0x0000045d --141号AU
kffixe[140].xptr.disk: 1 ; 0x470: 0x0001
kffixe[140].xptr.flags: 0 ; 0x472: L=0 E=0 D=0 S=0
kffixe[140].xptr.chk: 114 ; 0x473: 0x72
kffixe[141].xptr.au: 4294967295 ; 0x474: 0xffffffff
kffixe[141].xptr.disk: 65535 ; 0x478: 0xffff
kffixe[0]是272号文件的第61个AU,它的位置是1号盘1047号AU。注意,它就是一个间接AU。后面的kffixe[1]、kffixe[2],……,等等也都是间接AU了。
总结:
1)找到1号文件的第二个AU的位置,即kfffde[1],disk 1 au 72;
2)计算第二个au保存的位置,disk 1 au 72 blkn 16:此块保存的是272号文件的AU分布;
select 272 -255-1 from dual;
3)此块中kffde[0]到kffde[59],是272号文件的前60个au的位置信息(也就是前60M),被称为直接AU;
4)272号文件的第61个au,以及之后所有的au信息,保存在 kfffde[60]指向的AU位置 disk 0 ,AU 1047
5)读取disk 0,au 1047 ,从0号块开始读
6)从kffixe[0]开始,直到块中最后一个字节,都是272号文件的间接AU,如果0号块空间不够,那么继续用1号块存放272号文件的其余AU信息;
7)如果1047号au空间不足,那么,此au中最后一个kffixe结构将存放一个指针,指向下一个au
注意:直接AU的Struct叫kfffde,间接AU叫kffixe,结构都一样
--asm instance
set line 400 pagesize 1000
col name for a24
col type for a7
col extent for 99999
col path for a15
col failgrp for a10
col grp# for 999
col disk# for 9999
col file# for 9999
col au# for 999999
col au_size for 9999999
col dd for a100
select a.file_number as file#,a.name,x.xnum_kffxp as extent,a.group_number as grp#,d.disk_number as disk#,
au_kffxp as au#,dg.allocation_unit_size as au_size,
decode(x.lxn_kffxp,0,'PRIMARY',1,'MIRROR') AS type,d.failgroup as failgrp,d.path,
--'dd if='||path||' bs='||allocation_unit_size/1024||'k count=1 skip='||au_kffxp||' of=/tmp/test_1.dbf' as ou_t,
--'dd if=/tmp/test_1.dbf of=/tmp/test.dbf bs=1024k count=1 seek=0' as ou_i
'dd if='||path||' bs='||allocation_unit_size/1024||'k count=1 skip='||au_kffxp||' seek='||x.xnum_kffxp||' of=/tmp/'|| a.name as dd
from v$asm_alias a,x$kffxp x,v$asm_disk d,v$asm_diskgroup dg
where lower(a.name)='test02.dbf'
and x.group_kffxp=a.group_number
and x.group_kffxp=dg.group_number
and x.group_kffxp=d.group_number
and x.number_kffxp=a.file_number
and x.disk_kffxp=d.disk_number
and x.disk_kffxp <> 65534
order by x.xnum_kffxp;




