1. 打开sql跟踪 SYS AS SYSDBA >startup mount; SYS AS SYSDBA >alter session set sql_trace = true; SYS AS SYSDBA >alter database open; SYS AS SYSDBA >col name for a20 SYS AS SYSDBA >col value for a50
2. 查看跟踪文件: SYS AS SYSDBA >select * from v$diag_info where NAME='Default Trace File'; INST_ID|NAME |VALUE ----------|--------------------|-------------------------------------------------- 1|Default Trace File |/u01/diag/rdbms/hx/hx/trace/hx_ora_10720.trc 3. 格式化跟踪文件: SYS AS SYSDBA >show parameter timed_stat; NAME |TYPE |VALUE ------------------------------------|-----------|------------------------------ timed_statistics |boolean |TRUE SYS AS SYSDBA >show parameter dump_file_size; NAME |TYPE |VALUE ------------------------------------|-----------|------------------------------ max_dump_file_size |string |unlimited SYS AS SYSDBA >show parameter user_dump; NAME |TYPE |VALUE ------------------------------------|-----------|------------------------------ user_dump_dest |string |/u01/diag/rdbms/hx/hx/trace
4. 读取文件hx_ora_10634.txt,分析初始化过程: ******************************************************************************** SQL ID: 32r4f1brckzq1 Plan Hash: 0 create table bootstrap$ ( line# number not null, obj# number not null, sql_text varchar2(4000) not null) storage (initial 50K objno 59 extents (file 1 block 520)) 上面是第一个sql,可以看到,oracle在内存中创建这个表结构,数据是从file 1 block 520开始读取并加载的 看看file 1 block 520存放了哪个段的内容:
SYS AS SYSDBA >select SEGMENT_NAME,FILE_ID,BLOCK_ID,TABLESPACE_NAME from dba_extents where file_id=1 and block_id=520; SEGMENT_NAME | FILE_ID| BLOCK_ID|TABLESPACE_NAME -------------------------|----------|----------|-------------------- BOOTSTRAP$ | 1| 520|SYSTEM
SYS AS SYSDBA >select SEGMENT_NAME,FILE_ID,BLOCK_ID,blocks,TABLESPACE_NAME from dba_extents where SEGMENT_NAME='BOOTSTRAP$'; SEGMENT_NAME | FILE_ID| BLOCK_ID| BLOCKS|TABLESPACE_NAME -------------------------|----------|----------|----------|-------------------- BOOTSTRAP$ | 1| 520| 8|SYSTEM | 1| 520|SYSTEM
这个块存放的就是表BOOTSTRAP$的头块,这个表仅仅占用了一个区间。
继续跟踪文件: ******************************************************************************** SQL ID: 6apq2rjyxmxpj Plan Hash: 867914364 select line#, sql_text from bootstrap$ where obj# != :1
从上面看到,oracle在装载file 1 block 520后,就开始从这个表读取内容,实际上读取的是一些sql语句,然后利用这些sql语句创建数据库启动的必要对象: SYS AS SYSDBA >select line#,obj#,sql_text from bootstrap$ where rownum<=3; LINE#| OBJ#|SQL_TEXT ----------|----------|---------------------------------------------------------------------------------------------------- -1| -1|8.0.0.0.0 0| 0|CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 56K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO | |0 EXTENTS (FILE 1 BLOCK 128))
20| 20|CREATE TABLE ICOL$("OBJ#" NUMBER NOT NULL,"BO#" NUMBER NOT NULL,"COL#" NUMBER NOT NULL,"POS#" NUMBER | | NOT NULL,"SEGCOL#" NUMBER NOT NULL,"SEGCOLLENGTH" NUMBER NOT NULL,"OFFSET" NUMBER NOT NULL,"INTCOL# | |" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" V | |ARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 20 TABNO 4) CLUSTER C_OBJ#(BO#)
5. bootstrap$的生成与定位 那么,数据文件中的 bootstrap$是怎么生成的呢?那就要归功于创建数据库时候的sql.bsp文件了。隐含参数记录了这个文件: SYS AS SYSDBA >col ksppinm for a20 col ksppdesc for a40 col ksppstvl for a10 select ksppinm,ksppdesc,ksppstvl from sys.x$ksppi x,sys.x$ksppcv y where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and (x.ksppinm like '%&par%'); / Enter value for par: init_sql old 3: where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and (x.ksppinm like '%&par%') new 3: where x.inst_id = userenv('Instance') and y.inst_id = userenv('Instance') and x.indx = y.indx and (x.ksppinm like '%init_sql%')
KSPPINM |KSPPDESC |KSPPSTVL --------------------|----------------------------------------|---------- _init_sql_file |File containing SQL statements to execut|?/rdbms/ad |e upon database creation |min/sql.bs | |q
创建数据库的create database语句隐含就要执行sql.bsp中的内容,这个文件包含了许多个bsp文件,其中的dcore.bsq文件就有表bootstrap$的创建语句。 create table bootstrap$ ( line# number not null, /* statement order id */ obj# number not null, /* object number */ sql_text varchar2("M_VCSZ") not null) /* statement */ storage (initial 50K) /* to avoid space management during IOR I */ // /* "//" required for bootstrap */ 通过上面的分析,数据库在内存中建立表结构后,直接定位到file 1 block 520,从而继续后面的工作。那么,他怎么知道是这个块是bootstrap$段的头块呢?那就要看system表空间记录的root dba了。
10 STYLE FILE HEADER: Compatibility Vsn = 186646528=0xb200000 Db ID=763100300=0x2d7bfc8c, Db Name='HX' Activation ID=0=0x0 Control Seq=14715=0x397b, File size=51200=0xc800 File Number=1, Blksiz=8192, File Type=3 DATA Tablespace #0 - SYSTEM rel_fn:1 Creation at scn: 0x0000.00000009 02/06/2013 17:15:16 Backup taken at scn: 0x0000.000cec73 03/31/2013 21:44:20 thread:1 reset logs count:0x30817c6a scn: 0x0000.003cef48 prev reset logs count:0x305eefc2 scn: 0x0000.000c7def recovered at 05/12/2013 22:15:57 status:0x2004 root dba:0x00400208 chkpt cnt: 1095 ctl cnt:1094 begin-hot-backup file size: 41600 Checkpointed at scn: 0x0000.0054c1ba 05/13/2013 20:02:02 thread:1 rba:(0xa2.4d1e.10) 注意:只有system表空间的文件头才具备root dba,root dba只存在于system表空间的文件头中,用来定位数据库引导的bootstrap$信息。root dba一共4字节。 root dba(0x00400208)转换为2进制:0000000001 0000000000001000001000,前面10位表示文件号,就是1(/u01/oradata/hx/system01.dbf),后面22位表示数据文件1上的第520个块。
函数转换root dba(eygle大师的脚本): SYS AS SYSDBA >CREATE OR REPLACE FUNCTION getbfno (p_dba IN VARCHAR2) 2 RETURN VARCHAR2 3 IS 4 l_str VARCHAR2 (255) DEFAULT NULL; 5 BEGIN 6 l_str := 7 'datafile# is:' 8 || DBMS_UTILITY.data_block_address_file 9 (TO_NUMBER (LTRIM (p_dba, '0x'),'xxxxxxxx')) 10 || chr(10)||'datablock is:' 11 || DBMS_UTILITY.data_block_address_block 12 (TO_NUMBER (LTRIM (p_dba, '0x'),'xxxxxxxx')); 13 RETURN l_str; 14 END; 15 / col bfno for a20
Function created. SYS AS SYSDBA >select getbfno('&a') bfno from dual; Enter value for a: 00400208 old 1: select getbfno('&a') bfno from dual new 1: select getbfno('00400208') bfno from dual BFNO -------------------- datafile# is:1 datablock is:520