最近重拾了DSI 401,根据章节,大致做个笔记吧,以备后续的翻看。由于是断断续续的看的,所以下面的笔记的思路可能会有些跳跃。
第一、二章的dump,crash,corruption主要介绍的是数据库hang住,loop,还有crash的一些诊断。
loop和hang最大的区别就是loop消耗cpu,你可能会看到cpu使用率100%的情况,而hang的情况你会看到数据库基本没有压力。我个人觉得latch属于loop的情况,会不断的sleep/wake up,而且出现latch的时候,往往cpu中的user%部分会比较高。而hang的情况往往是数据库中的dml锁,前一个session的执行完成之后锁没释放,后一个session就只能等在那里了。
进行故障诊断的时候,我们可以查alertlog,trace file,application的log,coredump,syslog等等。
其中一个很重要的工具是oradebug hanganalyze,一般使用level 3进行分析。注意LEAF和LEAF_NW的节点。
dump systemstates可以用ass.awk来辅助分析trace文件。
下面是systemstates的tracefile中的几个解释:
通常情况下,一个process下是一个session,一个session开一个transaction。如果一个process下有多个session,一般是shared server模式或者OCI应用等等。因此在trace file中大致看到的也是这样的结构。最外层的时候process SO(SO:states objects,是SGA中的结构),里面是session的信息,再里面一层是transaction信息。
来看一个systemstate dump:
先看一个process states objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
PROCESS 17: ---------------------------------------- SO: 700000025e5ef20, type: 2, owner: 0, flag: INIT/-/-/0x00 (process) Oracle pid=17, calls cur/top: 70000002267efb0/700000025f9edc0, flag: (0) - int error: 0, call error: 0, sess error: 0, txn error 0 (post info) last post received: 0 0 0 last post received-location: No post last process to post me: none last post sent: 0 0 24 last post sent-location: ksasnd last process posted by me: 700000025e59880 1 6 (latch info) wait_event=0 bits=20 holding (efd=33) 7000000239479a0 Child library cache level=5 child#=3 Location from where latch is held: kglLockCursor: Context saved from call: 2 state=busy, wlstate=free waiters [orapid (seconds since: put on list, posted, alive check)]: 15 (4311, 1304283076, 3) 26 (4293, 1304283076, 3) 16 (4263, 1304283076, 3) 8 (4179, 1304283076, 3) 18 (3153, 1304283076, 3) 25 (3019, 1304283076, 3) 28 (2811, 1304283076, 3) 29 (1770, 1304283076, 3) 30 (1770, 1304283076, 3) 31 (390, 1304283076, 3) 32 (390, 1304283076, 3) waiter count=11 Process Group: DEFAULT, pseudo proc: 700000025ea17a8 O/S info: user: oracle1, term: UNKNOWN, ospid: 2592926 OSD pid info: Unix process pid: 2592926, image: oracle@sg2as059 (J000) ...... |
上述第3行SO: 700000025e5ef20 表示state object ID为700000025e5ef20 ,
第4行表示该Oracle pid为17
第5行表示是否有相关的ora-nnnn的报错。
第6~11行显示inter-process的信息。
第12行,latch信息
第31~32行os的一些信息.
再看一个session states objects:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
SO: 700000025f61ca0, type: 4, owner: 700000025e63de0, flag: INIT/-/-/0x00 (session) sid: 143 trans: 0, creator: 700000025e63de0, flag: (51) USR/- BSY/-/-/-/-/- DID: 0000-0000-00000000, short-term DID: 0000-0000-00000000 txn branch: 0 oct: 0, prv: 0, sql: 0, psql: 0, user: 0/SYS waiting for 'Streams AQ: qmn slave idle wait' blocking sess=0x0 seq=1 wait_time=0 seconds since wait started=4329 =0, =0, =0 Dumping Session Wait History for 'Streams AQ: qmn slave idle wait' count=1 wait_time=15874499 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343911 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343900 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343909 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343900 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343886 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343897 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343896 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343929 =0, =0, =0 for 'Streams AQ: qmn slave idle wait' count=1 wait_time=27343921 =0, =0, =0 temporary object counter: 0 ...... |
第1行:states objects id和owner
第2行:session的sid,已经一些flag信息,如:
USR表示是user session
BSY表示session is busy, it is in a call
DED表示session mark dead by user process
DEL表示session being delete(通过alter system kill session)
KIL表示session mark kill (通过alter system kill session)
第3行:resource id(DID)的一些信息。
第4行:事务的关系分支。
第5行:oct(oracle command tye),和prv(user privilege),和oracle user,这里显示是SYS。
第6行:session的等待事件。
另外查看hang或者loop的等待的时候,对于buffer热块,可以查x$kcbfwait;对于enqueue可以查x$ksqst。
第三章,memeory management和heap corruption。
oracle的内存分为heap-extents-chunks。
连续的extents组成heap,各种类型的chunks组成extents,类型分别有free,permanent,re-creatable等等。如果一个extents是从另一个heap延伸过来的,那么从延伸过来的那个heap叫父heap,当前的heap叫子heap。
当用户向heap申请free的chunk的时候,发现没有多余的space可供使用时,heap manager会去LRU中找unpinned(即re-createable)的chunks,使其释放。
一个granule最小为4M,而sga最小包含一个fix(含redo buffer),一个buffer cache,一个shared pool,所以一个sga最小为12M。
ora-600是heap中的一致性检验失败触发的。此外bug和存储损坏也会触发ora-600。
ora-7445一般是内存指针指向失败造成,比如指向内存越界的区域。此外,代码bug和内存地址计算错误也会触发ora-7445。
dump memory:
alter session|system set events ‘trace name heapdump|heapdump_addr|buffers|row_cache|library_cache level n;
或者
oradeug dump heapdump|heapdump_addr|buffers|row_cache|library_cache n;
其中上述的n,如果为1代表dump PGA,2为SGA,3为UGA,32为large pool。
heapdump能dump出:(1)内存描述符。(2)extents和chunks。(3)LRU,free list,permanent chunks等等。
heapdump_addr能dump出子heap,n为子heap的address。
查heap中的各项chunk信息,可以查x$ksmhp, 如果是sga中的信息,可以查x$ksmsp;如果是pga,可以查 x$ksmpp,如果是uga,可查x$ksmup;
第四章,data block dump.
data block分成3层结构:
cache layer
transaction layer
data layer(含footer)
rowid:格式,6363,oooooofffbbbbbbsss
常用:
dbms_rowid.ROWID_BLOCK_NUMBER
dbms_rowid.ROWID_CREATE
dbms_rowid.ROWID_RELATIVE_FNO
如何dump block:
1)用dd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
E:\ora8i\oracle\oradata\ora8i>dd bs=8192 if=USERS01.DBF count=1 |od -xv >111.txt 1+0 records in 1+0 records out E:\ora8i\oracle\oradata\ora8i> E:\ora8i\oracle\oradata\ora8i> E:\ora8i\oracle\oradata\ora8i>cat 111.txt 0000000000 0000 0000 1000 0000 6C00 0000 6C6D 6A6B 0000000020 0000 0000 0000 0000 0000 0000 0000 0000 …… 0000007640 0000 0000 0000 0000 0000 0000 0000 0000 0000007660 0000 0000 0000 0000 0000 0000 0000 0000 0000007700 0000 0000 0000 0000 0000 0000 0000 0000 0000007720 0000 0000 0000 0000 0000 0000 0000 0000 0000007740 0000 0000 0000 0000 0000 0000 0000 0000 0000007760 0000 0000 0000 0000 0000 0000 0000 0000 0000010000 020B 0000 0001 00C0 0000 0000 0000 0401 0000010020 88C9 0000 5000 0800 0000 0800 EED9 0A46 0000010040 524F 3841 0049 0000 02C9 0000 6C00 0000 0000010060 1000 0000 0003 0003 0000 0000 0000 0000 0000010100 0000 0000 0000 0000 0000 0000 0000 0000 0000010120 0000 0000 0000 0000 0000 0000 0000 0000 0000010140 0000 0000 144B 0000 0000 0000 8136 2CBD 0000010160 8119 2CBD 0001 0000 0000 0000 0000 0000 0000010200 0000 0000 0000 0000 0000 0004 30FB 0002 …… 0000017260 0000 0000 0000 0000 0000 0000 0000 0000 0000017300 0000 0000 0000 0000 0000 0000 0000 0000 0000017320 0000 0000 0000 0000 0000 0000 0000 0000 0000017340 0000 0000 0000 0000 0000 0000 0000 0000 0000017360 0000 0000 0000 0000 0000 0000 0000 0000 0000017400 0000 0000 0000 0000 0000 0000 0000 0000 0000017420 0000 0000 0000 0000 0000 0000 0000 0000 0000017440 0000 0000 0000 0000 0000 0000 0000 0000 0000017460 0000 0000 0000 0000 0000 0000 0000 0000 0000017500 0000 0000 0000 0000 0000 0000 0000 0000 0000017520 0000 0000 0000 0000 0000 0000 0000 0000 0000017540 0000 0000 0000 0000 0000 0000 0000 0000 0000017560 0000 0000 0000 0000 0000 0000 0000 0000 0000017600 0000 0000 0000 0000 0000 0000 0000 0000 0000017620 0000 0000 0000 0000 0000 0000 0000 0000 0000017640 0000 0000 0000 0000 0000 0000 0000 0000 0000017660 0000 0000 0000 0000 0000 0000 0000 0000 0000017700 0000 0000 0000 0000 0000 0000 0000 0000 0000017720 0000 0000 0000 0000 0000 0000 0000 0000 0000017740 0000 0000 0000 0000 0000 0000 0000 0000 0000017760 0000 0000 0000 0000 0000 0000 0B01 0000 0000020000 E:\ora8i\oracle\oradata\ora8i> |
dd出来的block的格式:2248842244,2位type+2位format+4位为将来用+8位RDBA+8位scn base+4位scn wrap+2位seq+2位flag+4位chkval+4位将来用。
tail为scn base的后2位+type+seq
2) 用alter system dump datafile xx block xx;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
Dump file E:\ora8i\oracle\admin\ora8i\udump\ORA07680.TRC Wed Jul 06 22:11:51 2011 ORACLE V8.1.7.0.0 - Production vsnsta=0 vsnsql=e vsnxtr=3 Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Instance name: ora8i Redo thread mounted by this instance: 1 Oracle process number: 9 Windows thread id: 7680, image: ORACLE.EXE *** SESSION ID:(8.45) 2011-07-06 22:11:51.839 Start dump data blocks tsn: 2 file#: 3 minblk 35 maxblk 35 buffer tsn: 2 rdba: 0x00c00023 (3/35) scn: 0x0000.00027f7e seq: 0x02 flg: 0x00 tail: 0x7f7e0602 frmt: 0x02 chkval: 0x0000 type: 0x06=trans data Block header dump: 0x00c00023 Object id on Block? Y seg/obj: 0xc78 csc: 0x00.27f7d itc: 1 flg: - typ: 1 - DATA fsl: 0 fnx: 0x0 ver: 0x01 Itl Xid Uba Flag Lck Scn/Fsc 0x01 xid: 0x0002.00e.00000073 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000 data_block_dump =============== tsiz: 0xfb8 hsiz: 0x14 pbl: 0x0abc6c44 bdba: 0x00c00023 flag=----------- ntab=1 nrow=1 frre=-1 fsbo=0x14 fseo=0xf8a avsp=0xf76 tosp=0xf76 0xe:pti[0] nrow=1 offs=0 0x12:pri[0] offs=0xf8a block_row_dump: tab 0, row 0, @0xf8a tl: 46 fb: --H-FL-- lb: 0x0 cc: 9 col 0: [ 3] 53 59 53 col 1: [ 1] 80 col 2: [ 4] 4f 50 45 4e col 3: *NULL* col 4: *NULL* col 5: [ 6] 53 59 53 54 45 4d col 6: [ 4] 54 45 4d 50 col 7: [ 7] 78 6f 05 08 11 2a 09 col 8: [ 9] 53 59 53 5f 47 52 4f 55 50 end_of_block_dump End dump data blocks tsn: 2 file#: 3 minblk 35 maxblk 35 |
注意data这部分可以通过asc转十六进制来翻译:
col 0: [ 3] 53 59 53
即为: S Y S
col 1: [ 1] 80
即为: €
col 2: [ 4] 4f 50 45 4e
即为: O P E N
col 3: *NULL*
col 4: *NULL*
col 5: [ 6] 53 59 53 54 45 4d
即为: S Y S T E M
col 6: [ 4] 54 45 4d 50
即为 T E M P
ora-600逻辑坏块,如块的scn base,seq以及tpye和footer不一致。
ora-1578,物理坏块。
注意dbv只能用在datafile上,不能用在redolog上。
flash freeze,可以通过event事件驱动,freeze之后,所有的状态都被冻结。
exp不会涉及上高水位之上的数据块,不会检查index和temporary的对象。
一个很有用的event:10231,在fts的时候,skip corrupt块,可用于设置之后的exp导出。再重建table,在导入。
block修复利器:bbed
set/dump/f/x/modify/sum apply/p/verify
第五章,index block dump
index block也是三层结构:
cache & tnx layer,即block header;注意,在这一层里含ITL信息。
branch & leaf,即common header;
row piece info
我们现在来dump一个索引块看看。
1.通过treedump来看索引的树状结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
--先查找object id: sys@ORA8I(127.0.0.1)> select data_object_id,object_id from dba_objects where object_name='IDX_T1'; DATA_OBJECT_ID OBJECT_ID -------------- ---------- 3193 3193 已用时间: 00: 00: 00.25 --根据object id 进行treedump sys@ORA8I(127.0.0.1)> alter session set events 'immediate trace name treedump level 3193'; 会话已更改。 已用时间: 00: 00: 00.50 sys@ORA8I(127.0.0.1)> exit |
以下是dump文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
Dump file E:\ora8i\oracle\admin\ora8i\udump\ORA01852.TRC Fri Jul 08 22:22:18 2011 ORACLE V8.1.7.0.0 - Production vsnsta=0 vsnsql=e vsnxtr=3 Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Instance name: ora8i Redo thread mounted by this instance: 1 Oracle process number: 9 Windows thread id: 1852, image: ORACLE.EXE *** 2011-07-08 22:22:18.973 *** SESSION ID:(8.167) 2011-07-08 22:22:18.910 ----- begin tree dump leaf: 0x40357e 4207998 (0: nrow: 1 rrow: 1) Leaf block dump =============== header address 1544966236=0x5c16505c kdxcolev 0 kdxcolok 0 kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y kdxconco 2 kdxcosdc 0 kdxconro 1 kdxcofbo 38=0x26 kdxcofeo 3929=0xf59 kdxcoavs 3891 kdxlespl 0 kdxlende 0 kdxlenxt 0=0x0 kdxleprv 0=0x0 kdxledsz 0 kdxlebksz 3940 row#0[3929] flag: -----, lock: 0 col 0; len 1; (1): 80 col 1; len 6; (6): 00 c0 00 23 00 00 ----- end of leaf block dump ----- ----- end tree dump |
我们看到该索引只有一个节点,只有一层。leaf block即为branch block,该地址用十六进制是0x40357e,如果是十进制是4207998。
kdxcoopc 0x80表示oracle8i以上的block,如果是70表示是oracle7的block,10表示IOT表的block,20表示键值压缩;
kdxcolev 0表示leaf的level,0表示是叶子。
kdxlenxt 表示next leaf block的地址。
kdxleprv 表示上一个leaf block的地址。
kdxledsz 0 如果是0表示非唯一索引,如果是非0表示唯一索引。
另外我们还可以用dump datafile block的方式dump出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
sys@ORA8I(127.0.0.1)> SELECT DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(4207998), 2 DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(4207998) 3 FROM dual; --注意我们这里使用的4207998是我们之前dump出来leaf block的十进制地址。 DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(4207998) DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(4207998) --------------------------------------------- ---------------------------------------------- 1 13694 已用时间: 00: 00: 00.32 sys@ORA8I(127.0.0.1)> --其实我们还可以根据dba的格式来转换也行: --4207998=>转换成二进制 --10000000011010101111110=>前面补零成32位 --00000000010000000011010101111110=>分割成前10位和后22位 --0000000001.0000000011010101111110=>前十位是file id,后22是block id --1.13694 --同样可得file id是1,block id是13694。 sys@ORA8I(127.0.0.1)> alter system dump datafile 1 block 13694; 系统已更改。 已用时间: 00: 00: 00.56 sys@ORA8I(127.0.0.1)> exit |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
Dump file E:\ora8i\oracle\admin\ora8i\udump\ORA09916.TRC Fri Jul 08 22:33:15 2011 ORACLE V8.1.7.0.0 - Production vsnsta=0 vsnsql=e vsnxtr=3 Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production Windows 2000 Version 5.1 Service Pack 3, CPU type 586 Instance name: ora8i Redo thread mounted by this instance: 1 Oracle process number: 9 Windows thread id: 9916, image: ORACLE.EXE *** 2011-07-08 22:33:15.156 *** SESSION ID:(8.170) 2011-07-08 22:33:15.094 Start dump data blocks tsn: 0 file#: 1 minblk 13694 maxblk 13694 buffer tsn: 0 rdba: 0x0040357e (1/13694) scn: 0x0000.00027f91 seq: 0x01 flg: 0x04 tail: 0x7f910601 frmt: 0x02 chkval: 0xa0c9 type: 0x06=trans data Block header dump: 0x0040357e Object id on Block? Y seg/obj: 0xc79 csc: 0x00.27f8f itc: 2 flg: - typ: 2 - INDEX fsl: 0 fnx: 0x0 ver: 0x01 Itl Xid Uba Flag Lck Scn/Fsc 0x01 xid: 0x0000.000.00000000 uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000 0x02 xid: 0x0001.01a.0000006e uba: 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000 Leaf block dump =============== header address 180120668=0xabc6c5c kdxcolev 0 kdxcolok 0 kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y kdxconco 2 kdxcosdc 0 kdxconro 1 kdxcofbo 38=0x26 kdxcofeo 3929=0xf59 kdxcoavs 3891 kdxlespl 0 kdxlende 0 kdxlenxt 0=0x0 kdxleprv 0=0x0 kdxledsz 0 kdxlebksz 3940 row#0[3929] flag: -----, lock: 0 col 0; len 1; (1): 80 col 1; len 6; (6): 00 c0 00 23 00 00 ----- end of leaf block dump ----- End dump data blocks tsn: 0 file#: 1 minblk 13694 maxblk 13694 |
我也可以看到了类似的leaf block的信息,我们还看到了leaf block有2个ITL。
event 10233能在索引进行rang scan操作时,skip掉逻辑损坏的索引块。
第六章,rollback segment corruption
说起事务,transaction,它的发生关系到2种segment,data segment和rollback segment。
data segment中有ITL和data row(注,ITL是在进行DML的那个data row的同一个数据块中),rollback segment头上有txn table(注,txn table中包含指向undo record的指针),后面有undo record(即原数据的镜像)。
txn id的组成为usn.tnx slot id+scn wrap
当data segment发生变化的时候,rollback segment中undo record也会对应的产生。
读一致(CR)的概念:当某session读取某个block的时候(这个block可能是在buffer中的),发现该block的ITL是被使用的,通过ITL找到rollback segment头中的txn table还是active状态,于是去读txn table中所指向的undo record。
锁的产生:DML后,未commit,则ITL为open状态,此时txn table还是active状态,所以就会等待。
当commit后,将tnx table 标记成inactive;注意此时data segment中的block未必会马上更新,即ITL还是open状态;直到这个block下次被读取的时候,ITL的状态才会被改成close。(即延时块清除)。使用延时块清除主要为了节省IO消耗(是指buffer中修改过的块,刷回到disk上,此部分消耗的IO)。
如果是rollback,则会undo原来的事务(从最近的开始,到最早的。),并且将ITL至于clear状态。rollback不存在延时块清除。注意在rollback的过程中会产生新的redo。会访问ITL,data block,rollback segment的header(因为有tnx table在那里),undo record。
当某个进程crash掉的时候,PMON会立即检测到,且开始回滚操作。
当数据库crash掉的时候,当再次open数据库的时候,开始做前滚。在system rollback segment中的事务会被立即回滚,在其他rollback segment中的事务会被mark成dead。
可以用x$ktxue.KTUXECFL=’DEAD’查询,另外,alter system dump undo header xxx的话,在trace文件中也能看到cflag也是0x10(即为DEAD)。
有2个隐含参数常常用于打开undo有问题的数据库:_corrupted_rollback_segment,_offline_rollback_segment。