环境:
- 00:24:16 sys@ORCL (^ω^) select * from v$version where rownum=1;
- BANNER
- --------------------------------------------------------------------------------
- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
我们要查询自己系统的一个表,则首先是去数据字典中找到该表的结构性信息。这些结构性信息存储在数据字典表中,但我们又从哪里获得数据字典表本身的结构性信息呢?虽然从表中我们可以查询到字典表本身的结构性信息,那在数据库open的时候最初是如何确定结构的?是写死在程序中呢?还是怎样处理的?oracle是怎么找到系统表空间的物理上的数据的?
- 23:48:02 sys@ORCL (^ω^) shutdown immediate
- 数据库已经关闭。
- 已经卸载数据库。
- ORACLE 例程已经关闭。
- 23:48:54 sys@ORCL (^ω^) startup mount
- ORACLE 例程已经启动。
- Total System Global Area 612368384 bytes
- Fixed Size 1250428 bytes
- Variable Size 192940932 bytes
- Database Buffers 411041792 bytes
- Redo Buffers 7135232 bytes
- 数据库装载完毕。
- 23:49:20 sys@ORCL (^ω^) alter session set sql_trace=true;
- 会话已更改。
- 23:49:44 sys@ORCL (^ω^) alter database open;
- 数据库已更改。
trc文件如下:
- =====================
- PARSING IN CURSOR #1 len=19 dep=0 uid=0 oct=35 lid=0 tim=18716803687 hv=1907384048 ad='33ecf028'
- alter database open
- END OF STMT
- PARSE #1:c=0,e=1749,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=18716803683
- =====================
第一个对象的创建:
- PARSING IN CURSOR #2 len=188 dep=1 uid=0 oct=1 lid=0 tim=18717747631 hv=1365064427 ad='33ec080c'
- create table bootstrap$ ( line# number not null, obj# number not null, sql_text varchar2(4000) not null) storage (initial 50K objno 56 extents (file 1 block 377))
- END OF STMT
- PARSE #2:c=0,e=549,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717747628
- EXEC #2:c=0,e=195,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=18717750171
- =====================
逐步提取内容,来建立数据字典表本身的结构
- PARSING IN CURSOR #2 len=55 dep=1 uid=0 oct=3 lid=0 tim=18717751282 hv=2111436465 ad='33ec0098'
- select line#, sql_text from bootstrap$ where obj# != :1
- END OF STMT
- PARSE #2:c=0,e=538,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717751278
- EXEC #2:c=0,e=35732,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717789730
- FETCH #2:c=0,e=1528,p=4,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=18717792281
- FETCH #2:c=0,e=43,p=0,cr=1,cu=0,mis=0,r=1,dep=1,og=4,tim=18717793026
- FETCH #2:c=0,e=34,p=0,cr=1,cu=0,mis=0,r=1,dep=1,og=4,tim=18717793574
- ..................................
先对bootstrap$做些观察:
- 00:05:00 sys@ORCL (^ω^) desc bootstrap$
- 名称 是否为空? 类型
- ----------------------------------------- -------- ----------------------------
- LINE# NOT NULL NUMBER
- OBJ# NOT NULL NUMBER
- SQL_TEXT NOT NULL VARCHAR2(4000)
- 00:05:42 sys@ORCL (^ω^) select count(1) from bootstrap$;
- COUNT(1)
- ----------
- 57
- 00:05:55 sys@ORCL (^ω^) select obj#,sql_text from bootstrap$ where rownum<11;
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- -1
- 8.0.0.0.0
- 0
- CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 M
- AXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9))
- 20
- CREATE TABLE ICOL$("OBJ#" NUMBER NOT NULL,"BO#" NUMBER NOT NULL,"COL#" NUMBER NO
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- T NULL,"POS#" NUMBER NOT NULL,"SEGCOL#" NUMBER NOT NULL,"SEGCOLLENGTH" NUMBER NO
- T NULL,"OFFSET" NUMBER NOT NULL,"INTCOL#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE
- 2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE
- 6" DATE) STORAGE ( OBJNO 20 TABNO 4) CLUSTER C_OBJ#(BO#)
- 40
- CREATE INDEX I_ICOL1 ON ICOL$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
- INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
- 40 EXTENTS (FILE 1 BLOCK 249))
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- 28
- CREATE TABLE CON$("OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"CON#" N
- UMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2
- (1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 M
- AXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645
- PCTINCREASE 0 OBJNO 28 EXTENTS (FILE 1 BLOCK 169))
- 48
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- CREATE UNIQUE INDEX I_CON1 ON CON$(OWNER#,NAME) PCTFREE 10 INITRANS 2 MAXTRANS 2
- 55 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCRE
- ASE 0 OBJNO 48 EXTENTS (FILE 1 BLOCK 313))
- 49
- CREATE UNIQUE INDEX I_CON2 ON CON$(CON#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STOR
- AGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 O
- BJNO 49 EXTENTS (FILE 1 BLOCK 321))
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- 15
- CREATE TABLE UNDO$("US#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"USER#" NU
- MBER NOT NULL,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"SCNBAS" NUMBER,"
- SCNWRP" NUMBER,"XACTSQN" NUMBER,"UNDOSQN" NUMBER,"INST#" NUMBER,"STATUS$" NUMBER
- NOT NULL,"TS#" NUMBER,"UGRP#" NUMBER,"KEEP" NUMBER,"OPTIMAL" NUMBER,"FLAGS" NUM
- BER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPA
- RE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
- STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREAS
- E 0 OBJNO 15 EXTENTS (FILE 1 BLOCK 105))
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- 34
- CREATE UNIQUE INDEX I_UNDO1 ON UNDO$(US#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STO
- RAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
- OBJNO 34 EXTENTS (FILE 1 BLOCK 201))
- 35
- CREATE INDEX I_UNDO2 ON UNDO$(NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (
- INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO
- OBJ#
- ----------
- SQL_TEXT
- --------------------------------------------------------------------------------
- 35 EXTENTS (FILE 1 BLOCK 209))
- 已选择10行。
由这里我们可以看出,bootstrap$ 中实际上是记录了一些数据库系统基本对象的创建语句。对我们的数据库来说,也可以看成是建立一个表结构,通过这个结构可以借助关系型数据库的方式去获取文件中的数据。
继续trc文件的内容
- =====================
- 在数据库系统表空间的头部创建了系统回滚段(block 9 开始,1---8 属于数据文件头)
- PARSING IN CURSOR #2 len=129 dep=1 uid=0 oct=36 lid=0 tim=18717824579 hv=0 ad='3e5398'
- CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9))
- END OF STMT
- PARSE #2:c=0,e=347,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717824575
- EXEC #2:c=0,e=111,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=18717826689
- =====================
这里同样是直接指定了该cluster 的段头位置 block 25。
- PARSING IN CURSOR #2 len=209 dep=1 uid=0 oct=4 lid=0 tim=18717827549 hv=0 ad='3e5398'
- CREATE CLUSTER C_OBJ#("OBJ#" NUMBER) PCTFREE 5 PCTUSED 40 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 136K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 2 EXTENTS (FILE 1 BLOCK 25)) SIZE 800
- END OF STMT
- PARSE #2:c=0,e=336,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717827546
- EXEC #2:c=0,e=125,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=18717829736
- 00:19:30 sys@ORCL (^ω^) select file_id,block_id from dba_extents where segment_name='C_OBJ#';
- FILE_ID BLOCK_ID
- ---------- ----------
- 1 25
- 1 33
- 1 41
- 1 3665
- 1 4929
- 1 5841
- 1 6105
- 1 6129
- 1 6153
- 1 6169
- 1 6193
- 1 6217
- 1 6249
- 1 6265
- 1 6281
- 1 6313
- 1 6409
- 1 7817
- 1 14601
- 1 27145
- 1 48905
- 1 56585
- 已选择22行。
我们可以看到,从tab$ 开始,存储发生了变化:STORAGE ( OBJNO 4 TABNO 1),那这里的 objno 4 tabno 1 表示什么意思呢?
- PARSING IN CURSOR #2 len=827 dep=1 uid=0 oct=1 lid=0 tim=18717834472 hv=4071397944 ad='33ebc484'
- CREATE TABLE TAB$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL,"FILE#" NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"BOBJ#" NUMBER,"TAB#" NUMBER,"COLS" NUMBER NOT NULL,"CLUCOLS" NUMBER,"PCTFREE$" NUMBER NOT NULL,"PCTUSED$" NUMBER NOT NULL,"INITRANS" NUMBER NOT NULL,"MAXTRANS" NUMBER NOT NULL,"FLAGS" NUMBER NOT NULL,"AUDIT$" VARCHAR2(38) NOT NULL,"ROWCNT" NUMBER,"BLKCNT" NUMBER,"EMPCNT" NUMBER,"AVGSPC" NUMBER,"CHNCNT" NUMBER,"AVGRLN" NUMBER,"AVGSPC_FLB" NUMBER,"FLBCNT" NUMBER,"ANALYZETIME" DATE,"SAMPLESIZE" NUMBER,"DEGREE" NUMBER,"INSTANCES" NUMBER,"INTCOLS" NUMBER NOT NULL,"KERNELCOLS" NUMBER NOT NULL,"PROPERTY" NUMBER NOT NULL,"TRIGFLAG" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 4 TABNO 1) CLUSTER C_OBJ#(OBJ#)
- END OF STMT
- PARSE #2:c=0,e=633,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717834468
- EXEC #2:c=0,e=169,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=18717836262
- 00:19:42 sys@ORCL (^ω^) select * from tab$ where obj# = 4 and tab# = 1;
- OBJ# DATAOBJ# TS# FILE# BLOCK# BOBJ# TAB#
- ---------- ---------- ---------- ---------- ---------- ---------- ----------
- COLS CLUCOLS PCTFREE$ PCTUSED$ INITRANS MAXTRANS FLAGS
- ---------- ---------- ---------- ---------- ---------- ---------- ----------
- AUDIT$
- ----------------------------------------------------------------------------
- ROWCNT BLKCNT EMPCNT AVGSPC CHNCNT AVGRLN AVGSPC_FLB
- ---------- ---------- ---------- ---------- ---------- ---------- ----------
- FLBCNT ANALYZETIME SAMPLESIZE DEGREE INSTANCES INTCOLS KERNELCOLS
- ---------- -------------- ---------- ---------- ---------- ---------- ----------
- PROPERTY TRIGFLAG SPARE1 SPARE2 SPARE3
- ---------- ---------- ---------- ---------- ----------
- SPARE4
- --------------------------------------------------------------------------------
- SPARE5
- --------------------------------------------------------------------------------
- SPARE6
- --------------
- 4 2 0 1 25 2 1
- 37 1 0 0 0 0 529
- --------------------------------------
- 1637 862 0 0 0 135 0
- 0 15-9月 -12 1637 37 37
- 1024 0 0
- 30-8月 -05
由这里可以看出,存储参数从这里开始,就从数据文件中固定表的记录中取出来。
由此再往trace文件看下去,就会发现这个时候数据库已经可以通过已有信息从系统表空间文件中提取结构信息和数据信息。
由上面内容我们可以看出,程序中只要提供 bootstrap$ 的创建脚本,确定好bootstap$的结构同时指定了段头的位置,然后就能通过段头去获取bootstrap$中的内容,而这些内容就是为一些字典表创建结构的sql_text,这样就因了bootstrap$这个天生的蛋,孵化出了c_obj#,tab$等等鸡,这些鸡又继续生蛋,则完成了数据库字典表结构的建立。所以,bootstrap$是oracle第一表!数据库每次启动的时候先创建bootstrap$来建立字典表本身的结构,然后再根据bootstrap$去获取数据文件的信息。创建 bootstrap$ 是在内存中进行的,不是真实的 物理对象,在内存中创建的对象恰好对应了 物理磁盘上的对象,这是固定位置的。
也就是说,oracle用关系型表来实现了自身结构的建立。
system表空间、sysaux表空间等这些物理对象都是已经真实地存在的,我们所做的“create”仅仅是在 SGA 中 创建这样一个对应的结构,然后好根据表的特征来读取数据,而为了生成 tab$ 等结构,这个结构的 sql 又来自 bootstrap$ ,最开始,oracle只要拥有了 bootstrap$ 的结构信息,在sga中创建了结构,则立即可以去system tablespace中获取bootstrap$的内容,然后逐步完成sga中字典表结构的建立。去system 表空间读取的bootstrap$内容,这些sql不需要重用,也不需要相关数据字典信息(也不可能有相关的数据字典信息)。任何一种数据结构,其结构的头部总是相对固定的。对于 db来说是在 system 固定位置。
开机流程如下:
1. 系统启动的时候根据control file的信息, 得到各个数据文件的位置.
2. 根据file# = 1 (system tablespace的第一个数据文件)的文件头的信息得到root dba的地址(此处为file_id = 1 ,block_id = 417
3. 根据root dba的信息, 得到bootstrap$对应的segment的存储位置, (此处为file_id = 1, block_id = 377) 得到系统启动的那只母鸡
4. 根据bootstrap$表中的信息, 得到系统中系统表的创建信息, 完成母鸡生下主要的小鸡的过程..
5.处理主要表生成之后的进一步处理, 生成主要的数据字典信息, 以及启动相关的undo segment(rollback segments).
6. 数据库启动完毕
数据库是个逻辑概念,但它是通过磁盘的物理存储实现的,那么在逻辑和物理之间怎么联系起来,那么就需要一个钩子,把二者挂在一起,其实,系统字典等在数据库创建后就存在了,数据库之所以逻辑化,就是为了好理解,好使用,在数据库启动的过程中,就需要把逻辑数据库和物理存储通过钩子挂起来,这就是BOOTSTRAP$,至于它的起始地址,在数据库创建的时候就确定了,我想可能是写在了磁盘的某个地方,不同的数据库可以不同.在OPEN前只所以创建了一些字典表,那是因为那些表并不需要读取表空间或数据文件里的信息,而是从其他地方获取,比如:初始化参数或控制文件,整个启动过程,就是把物理存储抽象成一个逻辑数据库的过程。
原文地址: http://blog.csdn.net/linwaterbin/article/details/7986097