環境:
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 mountORACLE 常式已經啟動。Total System Global Area 612368384 bytesFixed Size 1250428 bytesVariable Size 192940932 bytesDatabase Buffers 411041792 bytesRedo 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 openEND OF STMTPARSE #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 STMTPARSE #2:c=0,e=549,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717747628EXEC #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# != :1END OF STMTPARSE #2:c=0,e=538,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717751278EXEC #2:c=0,e=35732,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717789730FETCH #2:c=0,e=1528,p=4,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=18717792281FETCH #2:c=0,e=43,p=0,cr=1,cu=0,mis=0,r=1,dep=1,og=4,tim=18717793026FETCH #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)---------- 5700:05:55 sys@ORCL (^ω^) select obj#,sql_text from bootstrap$ where rownum<11; OBJ#----------SQL_TEXT-------------------------------------------------------------------------------- -18.0.0.0.0 0CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO 0 EXTENTS (FILE 1 BLOCK 9)) 20CREATE 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 NOT NULL,"OFFSET" NUMBER NOT NULL,"INTCOL#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 20 TABNO 4) CLUSTER C_OBJ#(BO#) 40CREATE INDEX I_ICOL1 ON ICOL$(OBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO40 EXTENTS (FILE 1 BLOCK 249)) OBJ#----------SQL_TEXT-------------------------------------------------------------------------------- 28CREATE TABLE CON$("OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"CON#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 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 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 48 EXTENTS (FILE 1 BLOCK 313)) 49CREATE UNIQUE INDEX I_CON2 ON CON$(CON#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 49 EXTENTS (FILE 1 BLOCK 321)) OBJ#----------SQL_TEXT-------------------------------------------------------------------------------- 15CREATE TABLE UNDO$("US#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"USER#" NUMBER 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" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 15 EXTENTS (FILE 1 BLOCK 105)) OBJ#----------SQL_TEXT-------------------------------------------------------------------------------- 34CREATE UNIQUE INDEX I_UNDO1 ON UNDO$(US#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0OBJNO 34 EXTENTS (FILE 1 BLOCK 201)) 35CREATE 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 STMTPARSE #2:c=0,e=347,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717824575EXEC #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 800END OF STMTPARSE #2:c=0,e=336,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717827546EXEC #2:c=0,e=125,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1871782973600: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 STMTPARSE #2:c=0,e=633,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,tim=18717834468EXEC #2:c=0,e=169,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=1871783626200: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 030-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前只所以建立了一些字典表,那是因為那些表並不需要讀取資料表空間或資料檔案裡的資訊,而是從其他地方擷取,比如:初始化參數或控制檔案,整個啟動過程,就是把實體儲存體抽象成一個邏輯資料庫的過程。