SQL> SELECT VALUE FROM V$DIAG_INFO WHERE NAME = "Default Trace File";
VALUE
-------------------------------------------------------------------------------
F:\ORACLE\PRODUCT\10.2.0\ADMIN\ORCL\UDUMP\orcl_ora_10076.trc
既然已經找到了轉儲文件,那就看看轉儲文件的內容:
Start dump data blocks tsn: 7 file#: 6 minblk 41 maxblk 41 --轉儲的文件號和塊號
buffer tsn: 7 rdba: 0x01800029 (6/41)
scn: 0x0000.000bddf9 seq: 0x01 flg: 0x04 tail: 0xddf92001
frmt: 0x02 chkval: 0x4b0e type: 0x20=FIRST LEVEL BITMAP BLOCK --這個表示它是一級位圖塊,直接和數據塊打交道
Hex dump of block: st=0, typ_found=1
Dump of First Level Bitmap Block
--------------------------------
nbits : 2 nranges: 1 parent dba: 0x0180002a poffset: 0 --標紅的表示它的父級位圖塊
unformatted: 12 total: 16 first useful block: 3
owning instance : 1
instance ownership changed at 04/20/2013 12:08:33
Last successful Search 04/20/2013 12:08:33
Freeness Status: nf1 0 nf2 1 nf3 0 nf4 0
Extent Map Block Offset: 4294967295
First free datablock : 3
Bitmap block lock opcode 0
Locker xid: : 0x0000.000.00000000
Inc #: 0 Objd: 52590
HWM Flag: HWM Set
Highwater:: 0x0180002d ext#: 0 blk#: 4 ext size: 16
#blocks in seg. hdr's freelists: 0
#blocks below: 1
mapblk 0x00000000 offset: 0
--------------------------------------------------------
DBA Ranges :
--------------------------------------------------------
0x01800029 Length: 16 Offset: 0
0:Metadata 1:Metadata 2:Metadata 3:25-50% free
4:unformatted 5:unformatted 6:unformatted 7:unformatted
8:unformatted 9:unformatted 10:unformatted 11:unformatted
12:unformatted 13:unformatted 14:unformatted 15:unformatted
--------------------------------------------------------
End dump data blocks tsn: 7 file#: 6 minblk 41 maxblk 41
-標紅的這些塊被用來存儲元數據,其餘的塊用來存儲數據,注意到總共有16個塊,full表示數據塊已經用完了。
如果這些塊用完的話,oracle就會使用二級位圖結構,以此類推,會出現三級位圖結構,oracle目前支持到三級位圖結構,上面的表示這些塊暫時未被使用,根據以上的說明oracle會從第4個塊(44)開始存放索引,索引的branch_code應該放在第44塊中,接下來我們就分析索引是如何分佈的。
下面是一個rdba轉換爲具體的文件和塊號的方法,後面會用到。
create or replace function getbfno(p_dba in varchar2)
return varchar2
is
l_str varchar2(255) default null;
begin
l_str :='datafile# is:'
||dbms_utility.data_block_address_file(TO_NUMBER(LTRIM(P_DBA,'0x'),'xxxxxxxx'))
||chr(10) ||'datablock is:'
||dbms_utility.data_block_address_block(TO_NUMBER(LTRIM(P_DBA,'0x'),'xxxxxxxx'));
return l_str;
end;
--去上面的rdba得到如下的轉換
SQL> select getbfno('0x01800029') from dual;
GETBFNO('0X01800029')
---------------------------------------------
datafile# is:6
datablock is:41
在開始插入索引前,我們下去看看 parent dba: 0x0180002a 這個裏面有什麼東西,也就是是二級位圖塊。
SQL> select getbfno('0x0180002a') from dual;
GETBFNO('0X0180002A')
-------------------------------------------------
datafile# is:6
datablock is:42
我們看到二級位圖塊是第42塊,轉儲42塊得到以下內容
*** 2013-04-20 15:30:52.140
*** SERVICE NAME:(SYS$USERS) 2013-04-20 15:30:52.125
*** SESSION ID:(121.797) 2013-04-20 15:30:52.125
Start dump data blocks tsn: 7 file#: 6 minblk 42 maxblk 42
buffer tsn: 7 rdba: 0x0180002a (6/42)
scn: 0x0000.000bddf2 seq: 0x01 flg: 0x04 tail: 0xddf22101
frmt: 0x02 chkval: 0x4be9 type: 0x21=SECOND LEVEL BITMAP BLOCK --表示它是二級位圖
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x09142200 to 0x09144200
9142200 0000A221 0180002A 000BDDF2 04010000 [!...*...........]
9142210 00004BE9 00000000 00000000 00000000 [.K..............]
9142220 00000000 00000000 00000000 00000000 [................]
Repeat 1 times
9142240 00000000 00000000 00000000 0180002B [............+...]
9142250 00000001 00000001 00000000 00000000 [................]
9142260 00000000 00000000 0000CD6E 00000001 [........n.......]
9142270 00000000 01800029 00010005 00000000 [....)...........]
9142280 00000000 00000000 00000000 00000000 [................]
Repeat 502 times
91441F0 00000000 00000000 00000000 DDF22101 [.............!..]
Dump of Second Level Bitmap Block
number: 1 nfree: 1 ffree: 0 pdba: 0x0180002b --此處它指向了43塊
Inc #: 0 Objd: 52590
opcode:0
xid:
L1 Ranges :
--------------------------------------------------------
0x01800029 Free: 5 Inst: 1 --在此處它指向了25塊,
這一塊用來記錄那些位圖塊管理單元被包含在對象中
--------------------------------------------------------
End dump data blocks tsn: 7 file#: 6 minblk 42 maxblk 42
在上面看到一塊,其中pdba指向了43塊,不明白是做什麼的,順便看一下
Dump of Second Level Bitmap Block
number: 1 nfree: 1 ffree: 0 pdba: 0x0180002b --此處它指向了43塊
Inc #: 0 Objd: 52590
opcode:0
43塊的內容經過轉儲內容如下:(中間省略了一部分省略了)
*** 2013-04-20 15:40:25.406
Start dump data blocks tsn: 7 file#: 6 minblk 43 maxblk 43
buffer tsn: 7 rdba: 0x0180002b (6/43)
scn: 0x0000.000bddf9 seq: 0x01 flg: 0x04 tail: 0xddf92301
frmt: 0x02 chkval: 0x66e9 type: 0x23=PAGETABLE SEGMENT HEADER
Hex dump of block: st=0, typ_found=1
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 16
last map 0x00000000 #maps: 0 offset: 2716
Highwater:: 0x0180002d ext#: 0 blk#: 4 ext size: 16
#blocks in seg. hdr's freelists: 0
#blocks below: 1
mapblk 0x00000000 offset: 0
Unlocked
--------------------------------------------------------
Low HighWater Mark :
Highwater:: 0x0180002d ext#: 0 blk#: 4 ext size: 16
#blocks in seg. hdr's freelists: 0
#blocks below: 1
mapblk 0x00000000 offset: 0
Level 1 BMB for High HWM block: 0x01800029 --此處標註了高低水位線
Level 1 BMB for Low HWM block: 0x01800029
--------------------------------------------------------
Segment Type: 2 nl2: 1 blksz: 8192 fbsz: 0
L2 Array start offset: 0x00001434
First Level 3 BMB: 0x00000000
L2 Hint for inserts: 0x0180002a
Last Level 1 BMB: 0x01800029
Last Level II BMB: 0x0180002a
Last Level III BMB: 0x00000000
Map Header:: next 0x00000000 #extents: 1 obj#: 52590 flag: 0x10000000
Inc # 0
Extent Map
-----------------------------------------------------------------
0x01800029 length: 16
Auxillary Map
--------------------------------------------------------
Extent 0 : L1 dba: 0x01800029 Data dba: 0x0180002c
--如果已經有空間被使用,則會指出該空間的第一個數據塊的位置,可以通過此處找到branch_code
--------------------------------------------------------
Second Level Bitmap block DBAs --此處記錄了二級位圖的地址
--------------------------------------------------------
DBA 1: 0x0180002a
End dump data blocks tsn: 7 file#: 6 minblk 43 maxblk 43
Block header dump: 0x0180002c
Object id on Block? Y
seg/obj: 0xcd6e csc: 0x00.c43b8 itc: 1 flg: E typ: 2 - INDEX
brn: 0 bdba: 0x1800029 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0004.018.00000189 0x00800639.0165.02 C--- 0 scn 0x0000.000c43b7
Branch block dump
=================
header address 152314444=0x914224c
kdxcolev 1
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 1
kdxconro 18
kdxcofbo 64=0x40
kdxcofeo 7898=0x1eda
kdxcoavs 7834
kdxbrlmc 25165871=0x180002f
kdxbrsno 17
kdxbrbksz 8060
kdxbr2urrc 0
row#0[8051] dba: 25165872=0x1800030 --從這可以看到葉子節點的存儲位置
col 0; len 3; (3): c2 06 2a
col 1; TERM
row#1[8042] dba: 25165873=0x1800031
col 0; len 3; (3): c2 0b 4b
col 1; TERM
row#2[8033] dba: 25165874=0x1800032
col 0; len 3; (3): c2 11 08
col 1; TERM
row#3[8024] dba: 25165875=0x1800033
col 0; len 3; (3): c2 16 29
col 1; TERM
row#4[8015] dba: 25165876=0x1800034
col 0; len 3; (3): c2 1b 4a
col 1; TERM
row#5[8006] dba: 25165877=0x1800035
col 0; len 3; (3): c2 21 07
col 1; TERM
row#6[7997] dba: 25165878=0x1800036
col 0; len 3; (3): c2 26 28
col 1; TERM
看到這兒要了解一下dump這個函數
dump 函數能查看錶中列在datafile存儲內容。
Oracle的NUMBER類型最多由三個部分構成,這三個部分分別是最高位表示位、數據部分、符號位。其中負數包含符號位,正數不會包括符號位(10進制即102)。另外,數值0比較特殊,它只包含一個數值最高位表示位80(16進制),沒有數據部分。
DUMP函數的輸出格式類似:
類型 <[長度]>,符號/指數位 [數字1,數字2,數字3,......,數字20]
各位的含義如下:
1.類型: Number型,Type=2 (類型代碼可以從Oracle的文檔上查到)
2.長度:指存儲的字節數
3.符號/指數位
在存儲上,Oracle對正數和負數分別進行存儲轉換:
正數:加1存儲(爲了避免Null)
負數:被101減,如果總長度小於21個字節,最後加一個102(是爲了排序的需要)
指數位換算:
正數:指數=符號/指數位 - 193 (最高位爲1是代表正數)
負數:指數=62 - 第一字節
4.從<數字1>開始是有效的數據位
從<數字1>開始是最高有效位,所存儲的數值計算方法爲:
將下面計算的結果加起來:
每個<數字位>乘以100^(指數-N) (N是有效位數的順序位,第一個有效位的N=0)
舉例說明
SQL> select dump(123456.789) from dual;
DUMP(123456.789)
-------------------------------
Typ=2 Len=6: 195,13,35,57,79,91
|
<指數>: 195 - 193 = 2
<數字1> 13 - 1 = 12 *100^(2-0) 120000
<數字2> 35 - 1 = 34 *100^(2-1) 3400
<數字3> 57 - 1 = 56 *100^(2-2) 56
<數字4> 79 - 1 = 78 *100^(2-3) .78
<數字5> 91 - 1 = 90 *100^(2-4) .009
123456.789
SQL> select dump(-123456.789) from dual;
DUMP(-123456.789)
----------------------------------
Typ=2 Len=7: 60,89,67,45,23,11,102
|
<指數> 62 - 60 = 2(最高位是0,代表爲負數)
<數字1> 101 - 89 = 12 *100^(2-0) 120000
<數字2> 101 - 67 = 34 *100^(2-1) 3400
<數字3> 101 - 45 = 56 *100^(2-2) 56
<數字4> 101 - 23 = 78 *100^(2-3) .78
<數字5> 101 - 11 = 90 *100^(2-4) .009
123456.789(-)
現在我們查看葉子節點
SQL> select getbfno('0x1800030') from dual;
GETBFNO('0X1800030')
-----------------------------------------------
datafile# is:6
datablock is:48
轉儲一下48號數據塊可以看到:
Block header dump: 0x01800030
Object id on Block? Y
seg/obj: 0xcd6e csc: 0x00.c16d6 itc: 2 flg: E typ: 2 - INDEX
brn: 0 bdba: 0x1800029 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0001.026.00000179 0x00800012.00cf.01 -BU- 1 fsc 0x0000.000c16d9
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
Leaf block dump
===============
header address 152314468=0x9142264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 1
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 2
kdxconro 533
kdxcofbo 1102=0x44e
kdxcofeo 1112=0x458
kdxcoavs 10
kdxlespl 0
kdxlende 0
kdxlenxt 25165873=0x1800031
kdxleprv 25165871=0x180002f
kdxledsz 0
kdxlebksz 8036
row#0[1112] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2a
col 1; len 6; (6): 01 80 00 1c 02 1c
row#1[1125] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2b
col 1; len 6; (6): 01 80 00 1c 02 1d
row#2[1138] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2c
col 1; len 6; (6): 01 80 00 1c 02 1e
row#3[1151] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2d
col 1; len 6; (6): 01 80 00 1c 02 1f
row#4[1164] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2e
col 1; len 6; (6): 01 80 00 1c 02 20後面省略
注意到以下:
row#0[8051] dba: 25165872=0x1800030 --從這可以看到葉子節點的存儲位置
col 0; len 3; (3): c2 06 2a --541
col 1; TERM
row#0[1112] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2a --541
col 1; len 6; (6): 01 80 00 1c 02 1c --rowid
分支節點存放了第一個葉子節點的值,這樣在進行範圍判斷時候直接使用葉子節點中的值來判斷值位於哪一個塊中。
刪除541這一行數據
row#0[1112] flag: ---D--, lock: 2, len=13 --表示數據已經被刪除
col 0; len 3; (3): c2 06 2a
col 1; len 6; (6): 01 80 00 1c 02 1c
row#0[8051] dba: 25165872=0x1800030
col 0; len 3; (3): c2 06 2a
col 1; TERM
發現branch_code並沒有刪除,還是指向了它,並且在葉子節點並沒有刪除它,所以當DELETE 和 insert 很頻繁的時候,索引會越來越龐大。
因爲使用DELETE刪除數據並不會刪除索引,只會標記爲索引無效。
下面我們來看這一行
row#1[1125] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2b -- 542
col 1; len 6; (6): 01 80 00 1c 02 1d
我們來更新這一行 ,將他的值變爲545 看看索引會發生什麼變化。
SQL> update test set id='545' where id='542';
已更新 1 行。
row#3[1112] flag: ------, lock: 2, len=13
col 0; len 3; (3): c2 06 2e
col 1; len 6; (6): 01 80 00 1c 02 1d
rowid是完全一樣的,同時發現一個問題
前面刪除的哪一行也不在了,541哪一行的索引沒有在出現,難道使用UPADATE 運算會刪除以前被刪除了的索引,這個是個疑問,在去試一下。好像是這樣的,這個問題還有待研究。
Leaf block dump
===============
header address 152314468=0x9142264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 2
kdxconro 533
kdxcofbo 1102=0x44e
kdxcofeo 1112=0x458
kdxcoavs 10
kdxlespl 0
kdxlende 1
kdxlenxt 25165873=0x1800031
kdxleprv 25165871=0x180002f
kdxledsz 0
kdxlebksz 8036
row#0[8023] flag: ---D--, lock: 2, len=13 --頭變成這樣了
col 0; len 3; (3): c2 06 2c --這一行被我update掉了,但是前面剛剛廢棄的索引不見了。
col 1; len 6; (6): 01 80 00 1c 02 1e
row#1[8010] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2d
col 1; len 6; (6): 01 80 00 1c 02 1f
row#2[7997] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 06 2e
這個問題希望大家共同探討。。。。
索引的update和delete操作就是這樣的,下面我們來做索引的分裂實驗。
SQL> create table test2(id number,name varchar2(100));
表已創建。
SQL> create index idx_test2 on test2(id);
索引已創建。
SQL> declare
2 begin
3 for i in 1..540
4
5 loop
6
7 insert into test2 values (i,'100');
8 commit;
9 end loop ;
10
11 end;
12
13 /
SQL> insert into test2 values(5,'100');
已創建 1 行。
發生了分裂
Block header dump: 0x0180006c
Object id on Block? Y
seg/obj: 0xcd7e csc: 0x00.c9fb3 itc: 1 flg: E typ: 2 - INDEX
brn: 0 bdba: 0x1800069 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.017.00000194 0x008000a0.011a.01 -BU- 1 fsc 0x0000.000c9fb5
Branch block dump
=================
header address 152314444=0x914224c
kdxcolev 1
KDXCOLEV Flags = - - -
kdxcolok 1
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 1
kdxconro 1
kdxcofbo 30=0x1e
kdxcofeo 8051=0x1f73
kdxcoavs 8021
kdxbrlmc 25165935=0x180006f
kdxbrsno 0
kdxbrbksz 8060
kdxbr2urrc 0
row#0[8051] dba: 25165936=0x1800070
col 0; len 3; (3): c2 03 50 --349
col 1; TERM
----- end of branch block dump -----
End dump data blocks tsn: 7 file#: 6 minblk 108 maxblk 108
SQL> select getbfno('0x1800070') from dual;
GETBFNO('0X1800070')
-----------------------------------------------
datafile# is:6
datablock is:112
此時我們分別轉儲111和112數據文件
111文件如下
Leaf block dump
===============
header address 152314468=0x9142264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 1
kdxconro 279
kdxcofbo 594=0x252
kdxcofeo 4499=0x1193
kdxcoavs 3917
kdxlespl 0
kdxlende 0
kdxlenxt 25165936=0x1800070
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[4511] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 02
col 1; len 6; (6): 01 80 00 5c 00 00
row#1[4523] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 03
col 1; len 6; (6): 01 80 00 5c 00 01
row#2[4535] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 04
col 1; len 6; (6): 01 80 00 5c 00 02
row#3[4547] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 05
col 1; len 6; (6): 01 80 00 5c 00 03
row#4[4559] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 06 --引起了拆分
col 1; len 6; (6): 01 80 00 5c 00 04
row#5[4499] flag: ------, lock: 2, len=12
col 0; len 2; (2): c1 06
col 1; len 6; (6): 01 80 00 5c 02 1c
row#6[4583] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 07
col 1; len 6; (6): 01 80 00 5c 00 05
row#7[4595] flag: ------, lock: 0, len=12
col 0; len 2; (2): c1 08
。。。。。。。