查找对象的数据块、RDBA、dump trace文件
SCOTT@ prod>select deptno,rowid,
2 dbms_rowid.rowid_relative_fno(rowid) file#,
3 dbms_rowid.rowid_block_number(rowid) block#,
4 dbms_rowid.rowid_row_number(rowid) row#,
5 dbms_rowid.rowid_object(rowid) object# from dept1;
DEPTNO ROWID FILE# BLOCK# ROW# OBJECT#
---------- ------------------ ---------- ---------- ---------- ----------
10 AAAU/WAAEAAAAITAAA 4 531 0 85974
20 AAAU/WAAEAAAAITAAB 4 531 1 85974
30 AAAU/WAAEAAAAITAAC 4 531 2 85974
40 AAAU/WAAEAAAAITAAD 4 531 3 85974
50 AAAU/WAAEAAAAIXAAA 4 535 0 85974
查询数据块的RDBA
SCOTT@ prod>select dbms_utility.make_data_block_address(4,535) from dual;
DBMS_UTILITY.MAKE_DATA_BLOCK_ADDRESS(4,535)
-------------------------------------------
16777751
知道数据块RDBA,查询数据位置
SCOTT@ prod>SELECT dbms_utility.data_block_address_file(16777751) file#,
2 dbms_utility.data_block_address_block(16777751) block# from dual;
FILE# BLOCK#
---------- ----------
4 535
dump出数据结构
SYS@ prod>alter session set events 'immediate trace name buffer level 16777751';
SYS@ prod>oradebug setmypid
SYS@ prod>alter system dump datafile 4 block 535;
SYS@ prod>oradebug tracefile_name;
/u01/app/oracle/diag/rdbms/prod/prod/trace/prod_ora_8395.trc
dump文件详解
*** 2014-02-25 15:18:12.359
Start dump data blocks tsn: 4 file#:4 minblk 531 maxblk 531
Block dump from cache:
Dump of buffer cache at level 4 for tsn=4, rdba=16777747
BH (0x2abfabe4) file#: 4 rdba: 0x01000213 (4/531) class: 1 ba: 0x2abbe000
set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 526,28
dbwrid: 0 obj: 85974 objn: 85974 tsn: 4 afn: 4 hint: f
hash: [0x3e28d250,0x3e28d250] lru: [0x2abfad64,0x2abfabbc]
ckptq: [NULL] fileq: [NULL] objq: [0x2abfad7c,0x2abfabd4]
st: XCURRENT md: NULL tch: 3
flags: only_sequential_access
LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
cr pin refcnt: 0 sh pin refcnt: 0
Block dump from disk:
buffer tsn: 4 rdba: 0x01000213 (4/531)
scn: 0x0000.005c0958 seq: 0x02 flg: 0x04 tail: 0x09580602
frmt: 0x02 chkval: 0x71f5 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
。。。
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.005c0956
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
bdba: 0x01000213
data_block_dump,data header at 0x60207c
解读trace文件
BH (0x2abfabe4) file#: 4 rdba: 0x01000213 (4/531) class: 1 ba: 0x2abbe000
--BH (0x2abfabe4) ,这是BH的HASH值
--rdba: 0x01000213 (4/531)rdba就是rowid中的相对文件号rfile#+block#块号。
--class: 1 对应X$BH.class --表示buffer header对应block的类型,1=data block。 --其他值见后面
--ba: 0x2abbe000 对应X$BH.BA,这是BUFFER中block address,是块在内存中的物理地址。
set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 526,28
-- set: 3:对应X$BH.STATE,CR(3)=作为一致性读镜像的数据块 --其他值见后面
dbwrid: 0 obj: 85974 objn: 85974 tsn: 4 afn: 4 hint: f
--obj: 85974,对应X$BH.OBJ ,也就是块上数据在哪个对象里-- dba_objects.DATA_OBJECT_ID
hash: [0x3e28d250,0x3e28d250] lru: [0x2abfad64,0x2abfabbc]
--对应x$bh.nxt_hash x$bh.prv_hash这里用链表,指出下一个及前一个BH的HASH值。如果这个hash chain上只有一个bh,则这里的前一个及后一个BH的hash值都是此BH
--对应x$bh.nxt_repl x$bh.prv_repl这里用链表,指出下一个及前一个BH的在LRU链上HASH值。
ckptq: [NULL] fileq: [NULL] objq: [0x2abfad7c,0x2abfabd4]
--ckptq: [NULL] 在检查点队列上的HASH值,这里为空
--fileq: [NULL] 在文件队列上的HASH值
--objq: [0x22ff8054,0x24839390] 对应x$bh.oq_nxt x$bh.oq_prv .对象队列HASH值
--objaq:对应x$bh.aq_nxt x$bh.aq_prv.辅助对象队列HASH值
st: XCURRENT md: NULL tch: 3
--st: XCURRENT 对应x$bh.state ----见下表
--tch: 3 对应X$BH.TCH,Touch的缩写,表示一个Buffer的访问次数--不过不是绝对,3秒内访问同一块,TCH不增加。与此相关的一个字段是:$BH.tim --Touch Time
flags: only_sequential_access
--flags: only_sequential_access 对应x$bh. FLAG
LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
--LSCN: [0x0.0] HSCN: [0xffff.ffffffff] 修改时的SCN--如记录有修改时的SCN,可以转换此十六进制为SCN进行对比
--LRBA: [0x0.0.0] 应该是最低REDO BYTE ADDRES,[0x0.0.0]对应日志号,块号,第几字节起。也可能会有HRBA ,recovery rba 。
cr pin refcnt: 0 sh pin refcnt: 0
Block dump from disk:
buffer tsn: 4 rdba: 0x01000213 (4/531)
--这个块的TSN 表空间号和RDBA
scn: 0x0000.005c0958 seq: 0x02 flg: 0x04 tail: 0x09580602
--SCN直接转换为用to_number函数转换为10进制就是数据库内查出的SCN了,是这个块的状态改变时的SCN
frmt: 0x02 chkval: 0x71f5 type: 0x06=trans data
--type:0x06(表/索引块)
--frmt: 0x01(v7) 0x02(v8)
数据块的事物槽
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.005c0956
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x03 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
-------------------------------------------------------------------------------------------
附:
flag中,每位代表如下含义:
bit bit
0 buffer_dirty 14 stale
1 notify_after_change 15 deferred_ping
2 mod_started 16 direct_access
3 block_has_been_logged 17 hash_chain_dump
4 temp_data 18 ignore_redo
5 being_written 19 only_sequential_access
6 waiting_for_write 20 prefetched_block
7 multiple_waiters 21 block_written_once
8 recovery_reading 22 logically_flushed
9 unlink_from_lock 23 resilvered_already
10 down_grade_lock 25 redo_since_read
11 clone_being_written 29 plugged_from_foreign_db
12 reading_as_CR 30 flush_after_writing
13 gotten_in_current_mode
class:表示buffer header对应block的类型:
1=data block, 9=2nd level bmb,
2=sort block, 10=3rd level bmb,
3=save undo block, 11=bitmap block,
4=segment header, 12=bitmap index block,
5=save undo header, 13=unused,
6=free list, 14=undo header,
7=extent map, 15=undo block
state:
0, FREE, no valid block image
1, XCUR, a current mode block, exclusive to this instance 正在被当前的instance独占。
2, SCUR, a current mode block, shared with other instances正在被当前的instance共享
3, CR, a consistent read (stale) block image 一致读
4, READ, buffer is reserved for a block being read from disk 正在从磁盘上读取块
5, MREC, a block in media recovery mode 处于介质恢复模式
6, IREC, a block in instance (crash) recovery mode处于实例恢复模式
0,'free',1,'xcur',2,'scur',
3,'cr', 4,'read',5,'mrec',
6,'irec',7,'write',8,'pi', 9,'memory'
10,'mwrite',11,'donated', 12,'protected',
13,'securefile', 14,'siop',15,'recckpt',
16, 'flashfree', 17, 'flashcur', 18, 'flashna'
lru_flag
SYS@ prod>select distinct(lru_flag) from x$bh;
LRU_FLAG
----------
6
4
8
0
X$BH.lru_flag 为0,对应在产LRU的冷端头--DSI中有。也可以通过DUMP buffer cache,搜索BH中LRU的值来计算0状态时BH的位置。
X$BH.lru_flag 为2,对应:lru-flags: moved_to_tail 在LRU热端
X$BH.lru_flag 为8,对应:lru-flags: hot_buffer 在LRU热端 ---据说还有一种状态是9,也是在热端。
X$BH.lru_flag 为4,对应:lru-flags: on_auxiliary_list
X$BH.lru_flag 为6,对应:lru-flags: moved_to_tail on_auxiliary_list 在辅助LRU
SYS@ prod>select lru_flag,tch,BA,decode(state,0,'free',1,'xcur',2,'scur',3,'cr', 4,'read',5,'mrec',6,'irec',7,'write',8,'pi', 9,'memory',10,'mwrite',11,'donated', 12,'protected', 13,'securefile', 14,'siop',15,'recckpt', 16, 'flashfree', 17, 'flashcur', 18, 'flashna') status from x$bh where FILE#=4 and DBABLK=531;
LRU_FLAG TCH BA STATUS
---------- ---------- -------- ----------
0 3 2ABBE000 xcur
SYS@ prod>select file#,block#,status from v$bh where objd=85974;
FILE# BLOCK# STATUS
---------- ---------- ----------
4 532 xcur
4 535 cr
4 535 xcur
4 530 cr
4 530 xcur
4 533 xcur
4 531 xcur
4 534 xcur
cache buffer中LRU、LRUW列表
数据块逻辑读过程:
1.前台进程发出查询语句select deptno from bys.test;
2.根据DBA计算HASH值,根据HASH值找到相应的Hash bucket
3.获取CBC LATCH,如获取失败,则将产生:latch:cache buffers chains
4.在CBC LATCH保护下,服务器进程扫描hash chain,查找是否有所需BH
5.如查找到所需BH,将在Buffer Header上加buffer pin锁(这里是读操作所以是共享锁(找到BH时的锁常见有:当前读锁、一致读锁或修改锁),如获取buffer pin失败(比如正在X模式申请S模式),会产生buffer busy waits等待),并根据BH中指定的块在内存中实际地址,读取buffer,并将结果返回前台进程。读取完毕(纳秒级)后,将再次获取CBC LATCH,释放buffer pin锁,再释放CBC LATCH。
大表的全表扫表过程:
大小表的界限是:_small_table_threshold,此参数中的VALUE 是数据块个数。
大表的全表扫描只使用辅助LRU,其块的TCH为1。这样做不对主LRU上的块进行冲击,同时也方便大表中块的重用。此时如有其它用户语句需要从辅助LRU上查找可用buffer,直接可以使用,节约时间。
_small_table_threshold的值在数据库启动的时候自动配置成BUFFER数量的2%。
数据块与小表的物理读过程:
1.大表全表扫描只使用辅助LRU,此时TCH=1,如此后再有对大表中某一行的读取,TCH=2。此时如果SMON进程醒来,或者遇到有其它物理读扫描到些块,会将此TCH=2的块移到主LRU热端头,lru_flag=8,TCH清零。
2.正常读取时,在辅助LRU上找到可用块后会将其移动到主LRU的冷端头,lru_flag=0,tch=1
3.主LRU的热端尾的块被挤出到冷端头时,TCH不变。
4.主LRU冷端最尾的块被挤出时,如TCH>=2时,也会被移动到热端头,TCH=0;
5.flush buffer_cache后查询,块都是TCH=0。SMON进程移动主LRU上TCH<2块到辅助LRU上时不清零。
(主LRU与辅助LRU上块的比例大致是:75%,25%。在数据库刚启动或者刚flush buffer_cache后所有buffer都在辅助LRU上。SMON进程每3秒会从主LRU冷端尾开始扫描,将TCH<2的块移动到辅助LRU,以此维护主LRU与辅助LRU上块的比例。主LRU上冷端和热端上块的比例是50%,这由隐含参数:_db_percent_hot_default决定的--默认值就是 50)
6.如果未查找到所需BH,将发生物理读。服务器进程将从磁盘上的相应数据文件中读取所需块,并将此块读入buffer cche中。
7.将块读入buffer cache中时,如何找到一个可以使用的buffer呢?下面步骤进行一步步解析。
8.首先在辅助LRU的最尾端向前查找可用buffer,TCH<2的块可以被重用。
9.如果辅助LRU最尾端的块是TCH<2的块,则将直接使用此块,并将其移动到主LRU的冷端头。
同时也会根据此块的DBA进行HASH,查找相应的HASH BUCKET,将此块加入到对应的HASH CHAIN上,并对BH中的相应信息进行修改(如对应X$BH中的LRU_FLAG,NXT_HASH、BA等字段的具体值)--此过程也需要相应的CBC LATCH /buffer pin锁的获取释放等。再把数据块的值返回前台进程,此时物理读就完成了。
10.如果辅助LRU最尾端的块是TCH>=2的块,则首先将此块移动到主LRU的热端头,同时TCH清零;然后在在辅助LRU上继续向前查找,直到找到可用的块---TCH<2。之后的过程和步骤9中的就一样了。(SMON每三秒时,服务器进程扫描空闲BUFFER时;都会把辅助LRU中TCH大于等于2的移到主的热端头)
11.如果在辅助LRU上搜索完毕扔未找到可以使用的块,则将从主LRU的冷端尾开始搜索。
12.如果主LRU最尾端的块是TCH<2的块,则将直接使用此块,并将其移动到主LRU的冷端头,TCH为1。如是TCH>=2的块,则将其移动到热端头,TCH清零。如果是脏块,则将其移动到主LRUW上。依此规则向前搜索查找可用块。(SMON每3秒,从主LRU冷端查找TCH小于2的非脏块到辅助LRU确保辅助LRU中有可用BUFFER)
13.如果从主LRU最尾端向前搜索了40%(隐含参数_db_block_max_scan_pct,11GR2后好像不太一样了?)还未找到可用块,则将触发DBWR写LRUW上的脏块--(CKPTQ队列的写不涉及LRUW,只有DBWR会写LRUW上脏块,并且写的是LRUW上的全部脏块-每三秒醒来也要全部写出LRUM上所有块才会休眠。写LRUW上脏块的步骤是:DBWR进程写时或者SMON进程每三秒醒来时(LRUW进程不像辅助LRUW那样,非DBWR进程也允许访问),会将主LRUW上的一部分脏块移动到辅助LRUW,然后在辅助LRUW上排序、写入磁盘;然后再从主LRUW上移动下一批,直到写出完毕再次进入睡眠。并且在DBWR写出过程中,会产生free buffer waits),写出后的buffer将重新挂载到辅助LRU上并变为可用。