查找对象的数据块、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.trcdump文件详解
*** 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 xcurcache 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上并变为可用。