版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、深入研究B樹索引(一)2010-03-2501:43摘要:本文對(duì)B樹索引的結(jié)構(gòu)、內(nèi)部管理等方面做了一個(gè)全面的介紹。同時(shí)深入探討了一些與B樹索引有關(guān)的廣為流傳的說(shuō)法,比如刪除記錄對(duì)索引的影響,定期重建索引能解決許多性能問(wèn)題等。B樹索引的相關(guān)概念索引與表一樣,也屬于段(segment)的一種。里面存放了用戶的數(shù)據(jù),跟表一樣需要占用磁盤空間。只不過(guò),在索引里的數(shù)據(jù)存放形式與表里的數(shù)據(jù)存放形式非常的不一樣。在理解索引時(shí),可以想象一本書,其中書的內(nèi)容就相當(dāng)于表里的數(shù)據(jù),而書前面的目錄就相當(dāng)于該表的索引。同時(shí),通常情況下,索引所占用的磁盤空間要比表要小的多,其主要作用是為了加快對(duì)數(shù)據(jù)的搜索速度,也可以用來(lái)
2、保證數(shù)據(jù)的唯一性。但是,索引作為一種可選的數(shù)據(jù)結(jié)構(gòu),你可以選擇為某個(gè)表里的創(chuàng)建索引,也可以不創(chuàng)建。這是因?yàn)橐坏﹦?chuàng)建了索引,就意味著oracle對(duì)表進(jìn)行DML(包才INSERTUPDATEDELETE時(shí),必須處理額外的工作量(也就是對(duì)索引結(jié)構(gòu)的維護(hù))以及存儲(chǔ)方面的開銷。所以創(chuàng)建索引時(shí),需要考慮創(chuàng)建索引所帶來(lái)的查詢性能方面的提高,與引起的額外的開銷相比,是否值得。從物理上說(shuō),索引通??梢苑譃椋悍謪^(qū)和非分區(qū)索引、常規(guī)B樹索引、位圖(bitmap)索引、翻轉(zhuǎn)(reverse)索引等。其中,B樹索引屬于最常見的索引,由于我們的這篇文章主要就是對(duì)B樹索引所做的探討,因此下面只要說(shuō)到索引,都是指B樹索引。B
3、樹索引是一個(gè)典型的樹結(jié)構(gòu),其包含的組件主要是:< !-if!supportLists->1)<!-endif->葉子節(jié)點(diǎn)(Leafnode):包含條目直接指向表里的數(shù)據(jù)行。< !-if!supportLists->2)<!-endif->分支節(jié)點(diǎn)(Branchnode):包含的條目指向索引里其他的分支節(jié)點(diǎn)或者是葉子節(jié)點(diǎn)。< !-if!supportLists->3)<!-endif->根節(jié)點(diǎn)(Rootnode):一個(gè)B樹索引只有一個(gè)根節(jié)點(diǎn),它實(shí)際就是位于樹的最頂端的分支節(jié)點(diǎn)??梢杂孟聢D一來(lái)描述B樹索引的結(jié)構(gòu)。其中,B表示分
4、支節(jié)點(diǎn),而L表示葉子節(jié)點(diǎn)。8口R4300R5必RjfiS10RI5POORI6ORI29R21911R3痣0R25口口600R.10的。RI11W5R171200R1S100R1。加口R12了卯町1伽R14對(duì)于分支節(jié)點(diǎn)塊(包括根節(jié)點(diǎn)塊)來(lái)說(shuō),其所包含的索引條目都是按照順序排列的(缺省是升序排列,也可以在創(chuàng)建索引時(shí)指定為降序排列)。每個(gè)索引條目(也可以叫做每條記錄)都具有兩個(gè)字段。第一個(gè)字段表示當(dāng)前該分支節(jié)點(diǎn)塊下面所鏈接的索引塊中所包含的最小鍵值;第二個(gè)字段為四個(gè)字節(jié),表示所鏈接的索引塊的地址,該地址指向下面一個(gè)索引塊。在一個(gè)分支節(jié)點(diǎn)塊中所能容納的記錄行數(shù)由數(shù)據(jù)塊大小以及索引鍵值的長(zhǎng)度決定。比如
5、從上圖一可以看到,對(duì)于根節(jié)點(diǎn)塊來(lái)說(shuō),包含三條記錄,分別為(0B1)、(500B2)、(1000B3),它們指向三個(gè)分支節(jié)點(diǎn)塊。其中的0、500和1000分別表示這三個(gè)分支節(jié)點(diǎn)塊所鏈接的鍵值的最小值。而B1、B2和B3則表示所指向的三個(gè)分支節(jié)點(diǎn)塊的地址。對(duì)于葉子節(jié)點(diǎn)塊來(lái)說(shuō),其所包含的索引條目與分支節(jié)點(diǎn)一樣,都是按照順序排列的(缺省是升序排列,也可以在創(chuàng)建索引時(shí)指定為降序排列)。每個(gè)索引條目(也可以叫做每條記錄)也具有兩個(gè)字段。第一個(gè)字段表示索引的鍵值,對(duì)于單列索引來(lái)說(shuō)是一個(gè)值;而對(duì)于多列索引來(lái)說(shuō)則是多個(gè)值組合在一起的。第二個(gè)字段表示鍵值所對(duì)應(yīng)的記錄行的ROWID,該ROWID是記錄行在表里的物理
6、地址。如果索引是創(chuàng)建在非分區(qū)表上或者索引是分區(qū)表上的本地索引的話,則該ROWID占用6個(gè)字節(jié);如果索引是創(chuàng)建在分區(qū)表上的全局索引的話,則該ROWID占用10個(gè)字節(jié)。知道這些信息以后,我們可以舉個(gè)例子來(lái)說(shuō)明如何估算每個(gè)索引能夠包含多少條目,以及對(duì)于表來(lái)說(shuō),所產(chǎn)生的索引大約多大。對(duì)于每個(gè)索引塊來(lái)說(shuō),缺省的PCTFRE時(shí)10%,也就是說(shuō)最多只能使用其中的90%。同時(shí)9i以后,這90%中也不可能用盡,只能使用其中的87%左右。也就是說(shuō),8KB的數(shù)據(jù)塊中能夠?qū)嶋H用來(lái)存放索引數(shù)據(jù)的空間大約為6488(8192X9冊(cè)X8a)個(gè)字節(jié)。假設(shè)我們有一個(gè)非分區(qū)表,表名為warecountd,其數(shù)據(jù)行數(shù)為130萬(wàn)行。
7、該表中有一個(gè)列,列名為goodid,其類型為char(8),那么也就是說(shuō)該goodid的長(zhǎng)度為固定值:8。同時(shí)在該列上創(chuàng)建了一個(gè)B樹索弓I。在葉子節(jié)點(diǎn)中,每個(gè)索引條目都會(huì)在數(shù)據(jù)塊中占一行空間。每一行用2到3個(gè)字節(jié)作為行頭,行頭用來(lái)存放標(biāo)記以及鎖定類型等信息。同時(shí),在第一個(gè)表示索引的鍵值的字段中,每一個(gè)索引列都有1個(gè)字節(jié)表示數(shù)據(jù)長(zhǎng)度,后面則是該列具體的值。那么對(duì)于本例來(lái)說(shuō),在葉子節(jié)點(diǎn)中的一行所包含的數(shù)據(jù)大致如下圖二所示:根節(jié)點(diǎn):分支節(jié).0R129R2190200R4300R340SR.7480500R9600RID699RI1_700R12_790R13792R14310R15900RI6310
8、05R17.1200R181300R191430RO1600R21葉子節(jié).-11cmi190200300403500600699700790機(jī)01005120014801600表的數(shù)從上圖可以看到,在本例的葉子節(jié)點(diǎn)中,一個(gè)索引條目占18個(gè)字節(jié)。同時(shí)我們知道8KB的數(shù)據(jù)塊中真正可以用來(lái)存放索引條目的空間為6488字節(jié),那么在本例中,一個(gè)數(shù)據(jù)塊中大約可以放360(6488/18)個(gè)索引條目。而對(duì)于我們表中的130萬(wàn)條記錄來(lái)說(shuō),則需要大約3611(1300000/360)個(gè)葉子節(jié)點(diǎn)塊。而對(duì)于分支節(jié)點(diǎn)里的一個(gè)條目(一行)來(lái)說(shuō),由于它只需保存所鏈接的其他索引塊的地址即可,而不需要保存具體的數(shù)據(jù)行在哪里,
9、因此它所占用的空間要比葉子節(jié)點(diǎn)要少。分支節(jié)點(diǎn)的一行中所存放的所鏈接的最小鍵值所需空間與上面所描述的葉子節(jié)點(diǎn)相同;而存放的索引塊的地址只需要4個(gè)字節(jié),比葉子節(jié)點(diǎn)中所存放的ROWID少了2個(gè)字節(jié),少的這2個(gè)字節(jié)也就是ROWID中用來(lái)描述在數(shù)據(jù)塊中的行號(hào)所需的空間。因此,本例中在分支節(jié)點(diǎn)中的一行所包含的數(shù)據(jù)大致如下圖三所示:OBL500B2100(3B3B1B2B31000L714mLsLIL2L3L5L6L7200R4300<KR7-430RS310R15900R,1650。600R.10儂9RI1500LA700L5310L60U犯L240CU1W5R171200RIS00RI。;G0RI
10、2了如町1血R14ORI29R21卯2190200300403500TO079CSI01005120012ooNN不_KKX.ZE從上圖可以看到,在本例的分支節(jié)點(diǎn)中,一個(gè)索引條目占16個(gè)字節(jié)。根據(jù)上面葉子節(jié)點(diǎn)相同的方式,我們可以知道一個(gè)分支索引塊可以存放大約405(6488/16)個(gè)索引條目。而對(duì)于我們所需要的3611個(gè)葉子節(jié)點(diǎn)來(lái)說(shuō),則總共需要大約9個(gè)分支索引塊。這樣,我們就知道了我們的這個(gè)索引有2層,第一層為1個(gè)根節(jié)點(diǎn),第二層為9個(gè)分支節(jié)點(diǎn),而葉子節(jié)點(diǎn)數(shù)為3611個(gè),所指向的表的行數(shù)為1300000行。但是要注意,在oracle的索引中,層級(jí)號(hào)是倒過(guò)來(lái)的,也就是說(shuō)假設(shè)某個(gè)索引有N層,則根節(jié)點(diǎn)
11、白層級(jí)號(hào)為N,而根節(jié)點(diǎn)下一層的分支節(jié)點(diǎn)的層級(jí)號(hào)為N-1,依此類推。對(duì)本例來(lái)說(shuō),9個(gè)分支節(jié)點(diǎn)所在的層級(jí)號(hào)為1,而根節(jié)點(diǎn)所在的層級(jí)號(hào)為2。深入研究B樹索引(二)2009-10-0222:12B樹索引的內(nèi)部結(jié)構(gòu)我們可以使用如下方式將B樹索引轉(zhuǎn)儲(chǔ)成樹狀結(jié)構(gòu)的形式而呈現(xiàn)出來(lái):altersessionsetevents'immediatetracenametreedumplevelINDEX_OBJECT_ID'比如,對(duì)于上面的例子來(lái)說(shuō),我們把創(chuàng)建在goodid上的名為idx_warecountd_goodid的索弓I轉(zhuǎn)儲(chǔ)出來(lái)。SQL>selectobject_idfromuser_
12、objectswhereobject_name='IDX_WARECOUNTD_GOODID'OBJECT_ID7378SQL>altersessionsetevents'immediatetracenametreedumplevel7378'打開轉(zhuǎn)儲(chǔ)出來(lái)的文件以后,我們可以看到類似下面的內(nèi)容:begintreedumpbranch:0x180eb0a25225994(0:nrow:9,level:2)branch:0x180eca125226401(-1:nrow:405,level:1)leaf:0x180eb0b25225995(-1:nrow:35
13、9rrow:359)leaf:0x180eb0c25225996(0:nrow:359rrow:359)leaf:0x180eb0d25225997(1:nrow:359rrow:359)leaf:0x180eb0e25225998(2:nrow:359rrow:359),branch:0x180ee3825226808(0:nrow:406,level:1)leaf:0x180eca025226400(-1:nrow:359rrow:359)leaf:0x180eca225226402(0:nrow:359rrow:359)leaf:0x180eca325226403(1:nrow:359r
14、row:359)leaf:0x180eca425226404(2:nrow:359rrow:359)其中,每一行的第一列表示節(jié)點(diǎn)類型:branch表示分支節(jié)點(diǎn)(包括根節(jié)點(diǎn)),而leaf則表示葉子節(jié)點(diǎn);第二列表示十六進(jìn)制表示的節(jié)點(diǎn)的地址;第三列表示十進(jìn)制表示的節(jié)點(diǎn)的地址;第四列表示相對(duì)于前一個(gè)節(jié)點(diǎn)的位置,根節(jié)點(diǎn)從0開始計(jì)算,其他分支節(jié)點(diǎn)和葉子節(jié)點(diǎn)從-1開始計(jì)算;第五列的nrow表示當(dāng)前節(jié)點(diǎn)中所含有的索引條目的數(shù)量。比如我們可以看到根節(jié)點(diǎn)中含有的nrow為9,表示根節(jié)點(diǎn)中含有9個(gè)索引條目,分別指向9個(gè)分支節(jié)點(diǎn);第六列中的level表示分支節(jié)點(diǎn)的層級(jí),對(duì)于葉子節(jié)點(diǎn)來(lái)說(shuō)level都是0o第六列中的rr
15、ow表示有效的索引條目(因?yàn)樗饕龡l目如果被刪除,不會(huì)立即被清除出索引塊中。所以nrow減rrow的數(shù)量就表示已經(jīng)被刪除的索引條目數(shù)量)的數(shù)量,比如對(duì)于第一個(gè)leaf來(lái)說(shuō),其rrow為359,也就是說(shuō)該葉子節(jié)點(diǎn)中存放了359個(gè)可用索引條目,分別指向表warecountd的359條記錄。上面這種方式以樹狀形式轉(zhuǎn)儲(chǔ)整個(gè)索引。同時(shí),我們可以轉(zhuǎn)儲(chǔ)一個(gè)索引節(jié)點(diǎn)來(lái)看看其中存放了些什么。轉(zhuǎn)儲(chǔ)的方式為:altersystemdumpdatafilefile#blockblock#;我們從上面轉(zhuǎn)儲(chǔ)結(jié)果中的第二行知道,索引的根節(jié)點(diǎn)的地址為25225994,因此我們先將其轉(zhuǎn)換為文件號(hào)以及數(shù)據(jù)塊號(hào)。SQL>sel
16、ectdbms_utility.data_block_address_file(25225994),2dbms_utility.data_block_address_block(25225994)fromdual;DBMS_UTILITY.DATA_BLOCK_ADDRESDBMS_UTILITY.DATA_BLOCK_ADDRES660170于是,我們轉(zhuǎn)儲(chǔ)根節(jié)點(diǎn)的內(nèi)容。SQL>altersystemdumpdatafile6block60170;打開轉(zhuǎn)儲(chǔ)出來(lái)的跟蹤文件,我們可以看到如下的索引頭部的內(nèi)容:headeraddress85594180=0x51a1044kdxcolev2KD
17、XCOLEVFlags=-kdxcolok0kdxcoopc0x80:pcode=0:iotflags=-isconverted=Ykdxconco2kdxcosdc0kdxconro8kdxcofbo44=0x2ckdxcofeo7918=0x1eeekdxcoavs7874kdxbrlmc25226401=0x180eca1kdxbrsno0kdxbrbksz8060其中的kdxcolev表示索引層級(jí)號(hào),這里由于我們轉(zhuǎn)儲(chǔ)的是根節(jié)點(diǎn),所以其層級(jí)號(hào)為2。對(duì)葉子節(jié)點(diǎn)來(lái)說(shuō)該值為0;kdxcolok表示該索引上是否正在發(fā)生修改塊結(jié)構(gòu)的事務(wù);kdxcoopc表示內(nèi)部操作代碼;kdxconco表示索引條
18、目中列的數(shù)量;kdxcosdc表示索引結(jié)構(gòu)發(fā)生變化的數(shù)量,當(dāng)你修改表里的某個(gè)索引鍵值時(shí),該值增加;kdxconro表示當(dāng)前索引節(jié)點(diǎn)中索引條目的數(shù)量,但是注意,不包括kdxbrlmc指針;kdxcofbo表示當(dāng)前索引節(jié)點(diǎn)中可用空間的起始點(diǎn)相對(duì)當(dāng)前塊的位移量;kdxcofeo表示當(dāng)前索引節(jié)點(diǎn)中可用空間的最尾端的相對(duì)當(dāng)前塊的位移量;kdxcoavs表示當(dāng)前索引塊中的可用空間總量,也就是用kdxcofeo減去kdxcofbo得到的。kdxbrlmc表示分支節(jié)點(diǎn)的地址,該分支節(jié)點(diǎn)存放了索引鍵值小于row#0(在轉(zhuǎn)儲(chǔ)文檔后半部分顯示)所含有的最小值的所有節(jié)點(diǎn)信息;kdxbrsno表示最后一個(gè)被修改的索引條
19、目號(hào),這里看到是0,表示該索引是新建的索引;kdxbrbksz表示可用數(shù)據(jù)塊的空間大小。實(shí)際從這里已經(jīng)可以看到,即便是PCTFRE段置為0,也不能用足8192字節(jié)。再往下可以看到如下的內(nèi)容。這部分內(nèi)容就是在根節(jié)點(diǎn)中所記錄的索引條目,總共是8個(gè)條目。再加上row#08043dba:25226808=0x180ee38col0;len8;(8):3130303030333932col1;len3;(3):01401arow#77918dba:25229599=0x180f91fcol0;len8;(8):3130303131323033col1;len4;(4):01408fa5kdxbrlmc所
20、指向的第一個(gè)分支節(jié)點(diǎn),我們知道該根節(jié)點(diǎn)中總共存放了9個(gè)分支節(jié)點(diǎn)的索引條目,而這正是我們?cè)谇懊嫠赋龅臑榱斯芾?611個(gè)葉子節(jié)點(diǎn),我們需要9個(gè)分支節(jié)點(diǎn)。每個(gè)索引條目都指向一個(gè)分支節(jié)點(diǎn)。其中col1表示所鏈接的分支節(jié)點(diǎn)的地址,該值經(jīng)過(guò)一定的轉(zhuǎn)換以后實(shí)際就是row#所在彳T的dba的值。如果根節(jié)點(diǎn)下沒有其他的分支節(jié)點(diǎn),則col1為TERMcol0表示該分支節(jié)點(diǎn)所鏈接的最小鍵值。其轉(zhuǎn)換方式非常復(fù)雜,比如對(duì)于row#0來(lái)說(shuō),col0為3130303030303033,則將其中每對(duì)值都使用函數(shù)to_number(NN,'XX)的方式從十六進(jìn)制轉(zhuǎn)換為十進(jìn)制,于是我們得到轉(zhuǎn)換后的值:49,48,48,
21、48,48,48,48,51,因?yàn)槲覀円呀?jīng)知道索引鍵值是char類型的,所以對(duì)每個(gè)值都運(yùn)用chr函數(shù)就可以得到被索引鍵值為:1000000&實(shí)際上,對(duì)10000003運(yùn)用dump函數(shù)得到的結(jié)果就是:49,48,48,48,48,48,48,51。所以我們也就知道,10000003就是dba為25226808的索引塊所鏈接的最小鍵值。SQL>selectdump('10000003')fromdual;DUMP('10000003')Typ=96Len=8:49,48,48,48,48,48,48,50接下來(lái),我們從根節(jié)點(diǎn)中隨便找一個(gè)分支節(jié)點(diǎn),假設(shè)就
22、是row#0所描述的25226808。對(duì)其運(yùn)用前面所介紹過(guò)的dbms_utility里的存儲(chǔ)過(guò)程獲得其文件號(hào)和數(shù)據(jù)塊號(hào),并對(duì)該數(shù)據(jù)塊進(jìn)行轉(zhuǎn)儲(chǔ),其內(nèi)容加下所示。可以row#08043dba:25226402=0x180eca2col0;len8;(8):3130303030333933col1;len3;(3):01402erow#404853dba:25226806=0x180ee36col0;len8;(8):3130303031363430col1;len3;(3):014009endofbranchblockdump發(fā)現(xiàn)內(nèi)容與根節(jié)點(diǎn)完全類似,只不過(guò)該索引塊中所包含的索引條目(指向葉子節(jié)點(diǎn)
23、)的數(shù)量更多了,為405個(gè)。這也與我們前面所說(shuō)的一個(gè)分支索引塊可以存放大約405(6488/16)個(gè)索引條目完全一致。然后,我們從中隨便挑一個(gè)葉子節(jié)點(diǎn),對(duì)其進(jìn)行轉(zhuǎn)儲(chǔ)。假設(shè)就選row#0行所指向的葉子節(jié)點(diǎn),根據(jù)dba的值:25226402可以知道,文件號(hào)為6,數(shù)據(jù)塊號(hào)為60578。將其轉(zhuǎn)儲(chǔ)以后,其內(nèi)容如下所示,我只顯示與分支節(jié)點(diǎn)不同的部分。kdxlespl0kdxlende0kdxlenxt25226403=0x180eca3kdxleprv25226400=0x180eca0kdxledsz0kdxlebksz8036其中的kdxlespl表示當(dāng)葉子節(jié)點(diǎn)被拆分時(shí)未提交的事務(wù)數(shù)量;kdxlend
24、e表示被刪除的索引條目的數(shù)量;kdxlenxt表示當(dāng)前葉子節(jié)點(diǎn)的下一個(gè)葉子節(jié)點(diǎn)的地址;kdxlprv表示當(dāng)前葉子節(jié)點(diǎn)的上一個(gè)葉子節(jié)點(diǎn)的地址;kdxledsz表示可用空間,目前是0轉(zhuǎn)儲(chǔ)文件中接下來(lái)的部分就是索引條目部分,每個(gè)條目包含一個(gè)ROWID指向一個(gè)表里的數(shù)據(jù)行。如下所示。其中flag表示標(biāo)記,比如刪除標(biāo)記等;而lock表示鎖定信息。col0表示索引鍵值,其算法與我們?cè)谇懊娼榻B分支節(jié)點(diǎn)時(shí)所說(shuō)的算法一致。col1表示ROWID我們同樣可以看到,該葉子節(jié)點(diǎn)中包含了359個(gè)索引條目,與我們前面所估計(jì)的一個(gè)葉子節(jié)點(diǎn)中大約可以放360個(gè)索引條目也是基本一致的。row#08018flag:,lock:0
25、col0;len8;(8):3130303030333933col1;len6;(6):01402e930016row#18000flag:,lock:0col0;len8;(8):3130303030333933col1;len6;(6):01402ee7000eJJJJrow#3581574flag:,lock:0col0;len8;(8):3130303030333937col1;len6;(6):014018ba001fendofleafblockdump深入研究B樹索引(三)2009-10-0222:13B樹索引的訪問(wèn)我們已經(jīng)知道了B樹索引的體系結(jié)構(gòu),那么當(dāng)oracle需要訪問(wèn)索引里
26、的某個(gè)索引條目時(shí),oracle是如何找到該索引條目所在的數(shù)據(jù)塊的呢?當(dāng)oracle進(jìn)程需要訪問(wèn)數(shù)據(jù)文件里的數(shù)據(jù)塊時(shí),oracle會(huì)有兩種類型的I/O操作方式:<!-if!supportLists->1)<!-endif->隨機(jī)訪問(wèn),每次讀取一個(gè)數(shù)據(jù)塊(通過(guò)等待事件“dbfilesequentialread”體現(xiàn)出來(lái))。<!-if!supportLists->2)<!-endif->順序訪問(wèn),每次讀取多個(gè)數(shù)據(jù)塊(通過(guò)等待事件“dbfilescatteredread”體現(xiàn)出來(lái))。第一種方式則是訪問(wèn)索引里的數(shù)據(jù)塊,而第二種方式的I/O操作屬于全表掃描。
27、這里順帶有一個(gè)問(wèn)題,為何隨機(jī)訪問(wèn)會(huì)對(duì)應(yīng)到dbfilesequentialread等待事件,而順序訪問(wèn)則會(huì)對(duì)應(yīng)到dbfilescatteredread等待事件呢?這似乎反過(guò)來(lái)了,隨機(jī)訪問(wèn)才應(yīng)該是分散(scattered)的,而順序訪問(wèn)才應(yīng)該是順序(sequential)的。其實(shí),等待事件主要根據(jù)實(shí)際獲取物理I/O塊的方式來(lái)命名的,而不是根據(jù)其在I/O子系統(tǒng)的邏輯方式來(lái)命名的。下面對(duì)于如何獲取索引數(shù)據(jù)塊的方式中會(huì)對(duì)此進(jìn)行說(shuō)明。我們看到前面對(duì)B樹索引的體系結(jié)構(gòu)的描述,可以知道其為一個(gè)樹狀的立體結(jié)構(gòu)。其對(duì)應(yīng)到數(shù)據(jù)文件里的排列當(dāng)然還是一個(gè)平面的形式,也就是像下面這樣。因此,當(dāng)oracle需要訪問(wèn)某個(gè)索引
28、塊的時(shí)候,勢(shì)必會(huì)在這個(gè)結(jié)構(gòu)上跳躍的移動(dòng)。/根/分支/分支/葉子/,/葉子/分支/葉子/葉子/,/葉子/分支/葉子/葉子/,/葉子/分支/.當(dāng)oracle需要獲得一個(gè)索引塊時(shí),首先從根節(jié)點(diǎn)開始,根據(jù)所要查找的鍵值,從而知道其所在的下一層的分支節(jié)點(diǎn),然后訪問(wèn)下一層的分支節(jié)點(diǎn),再次同樣根據(jù)鍵值訪問(wèn)再下一層的分支節(jié)點(diǎn),如此這股,最終訪問(wèn)到最底層的葉子節(jié)點(diǎn)??梢钥闯?,其獲得物理I/O塊時(shí),是一個(gè)接著一個(gè),按照順序,串行進(jìn)行的。在獲得最終物理塊的過(guò)程中,我們不能同時(shí)讀取多個(gè)塊,因?yàn)槲覀冊(cè)跊]有獲得當(dāng)前塊的時(shí)候是不知道接下來(lái)應(yīng)該訪問(wèn)哪個(gè)塊的。因此,在索引上訪問(wèn)數(shù)據(jù)塊時(shí),會(huì)對(duì)應(yīng)到dbfilesequential
29、read等待事件,其根源在于我們是按照順序從一個(gè)索引塊跳到另一個(gè)索引塊,從而找到最終的索引塊的。那么對(duì)于全表掃描來(lái)說(shuō),則不存在訪問(wèn)下一個(gè)塊之前需要先訪問(wèn)上一個(gè)塊的情況。全表掃描時(shí),oracle知道要訪問(wèn)所有的數(shù)據(jù)塊,因此唯一的問(wèn)題就是盡可能高效的訪問(wèn)這些數(shù)據(jù)塊。因此,這時(shí)oracle可以采用同步的方式,分幾批,同時(shí)獲取多個(gè)數(shù)據(jù)塊。這幾批的數(shù)據(jù)塊在物理上可能是分散在表里的,因此其對(duì)應(yīng)至Udbfilescatteredread等待事件。深入研究B樹索引(四)2009-10-0222:18B樹索引的管理機(jī)制4.1B樹索引的對(duì)于插入(INSERT的管理對(duì)于B樹索引的插入情況的描述,可以分為兩種情況:一
30、種是在一個(gè)已經(jīng)充滿了數(shù)據(jù)的表上創(chuàng)建索引時(shí),索引是怎么管理的;另一種則是當(dāng)一行接著一行向表里插入或更新或刪除數(shù)據(jù)時(shí),索引是怎么管理的。對(duì)于第一種情況來(lái)說(shuō),比較簡(jiǎn)單。當(dāng)在一個(gè)充滿了數(shù)據(jù)的表上創(chuàng)建索引(createindex命令)時(shí),oracle會(huì)先掃描表里的數(shù)據(jù)并對(duì)其進(jìn)行排序,然后生成葉子節(jié)點(diǎn)。生成所有的葉子節(jié)點(diǎn)以后,根據(jù)葉子節(jié)點(diǎn)的數(shù)量生成若干層級(jí)的分支節(jié)點(diǎn),最后生成根節(jié)點(diǎn)。這個(gè)過(guò)程是很清晰的。但是對(duì)于第二種情況來(lái)說(shuō),會(huì)復(fù)雜很多。我們結(jié)合一個(gè)例子來(lái)說(shuō)明。為了方便起見,我們?cè)谝粋€(gè)數(shù)據(jù)塊為2KB的表空間上創(chuàng)建一個(gè)測(cè)試表,并為該表創(chuàng)建一個(gè)索引,該索引同樣位于2KB的表空間上。SQL>createt
31、ableindex_test(idchar(150)tablespacetbs_2k;SQL>createindexidx_testonindex_test(id)tablespacetbs_2k;當(dāng)一開始在一個(gè)空的表上創(chuàng)建索引的時(shí)候,該索引沒有根節(jié)點(diǎn),只有一個(gè)葉子節(jié)點(diǎn)。我們以樹狀形式轉(zhuǎn)儲(chǔ)上面的索引idx_testoSQL>selectobject_idfromuser_objectswhereobject_name='IDX_TEST'OBJECT_ID7390SQL>altersessionsetevents'immediatetracenamet
32、reedumplevel7390'從轉(zhuǎn)儲(chǔ)文件可以看到,該索引中只有一個(gè)葉子節(jié)點(diǎn)(leaf)。begintreedumpleaf:0x1c001a229360546(0:nrow:0rrow:0)endtreedump隨著數(shù)據(jù)不斷被插入表里,該葉子節(jié)點(diǎn)中的索引條目也不斷增加,當(dāng)該葉子節(jié)點(diǎn)充滿了索引條目而不能再放下新的索引條目時(shí),該索引就必須擴(kuò)張,必須再獲取一個(gè)可用的葉子節(jié)點(diǎn)。這時(shí),索引就包含了兩個(gè)葉子節(jié)點(diǎn),但是兩個(gè)葉子節(jié)點(diǎn)不可能單獨(dú)存在的,這時(shí)它們兩必須有一個(gè)上級(jí)的分支節(jié)點(diǎn),其實(shí)這也就是根節(jié)點(diǎn)了。于是,現(xiàn)在,我們的索引應(yīng)該具有3個(gè)索引塊,一個(gè)根節(jié)點(diǎn),兩個(gè)葉子節(jié)點(diǎn)。我們來(lái)做個(gè)試驗(yàn)看看這個(gè)過(guò)
33、程。我們先試著插入插入10條記錄。注意,對(duì)于2KB的索引塊同時(shí)PCTFRE囪缺省的10%來(lái)說(shuō),只能使用其中大約1623字節(jié)(2048X90%X88%)。對(duì)于表index_test來(lái)說(shuō),葉子節(jié)點(diǎn)中的每個(gè)索引條目所占的空間大約為161個(gè)字節(jié)(3個(gè)字節(jié)行頭+1個(gè)字節(jié)列長(zhǎng)+150個(gè)字節(jié)列本身+1個(gè)字節(jié)列長(zhǎng)+6個(gè)字節(jié)ROWID,那么當(dāng)我們插入將10條記錄以后,將消耗掉大約1610個(gè)字節(jié)。SQL>begin2 foriin1.10loop3 insertintoindex_testvalues(rpad(to_char(i*2),150,'a');4 endloop;5 end;6
34、/SQL>commit;SQL>selectfile_id,block_id,blocksfromdba_extentswheresegment_name='IDX_TEST'FILE_IDBLOCK_IDBLOCKS741732SQL>altersystemdumpdatafile7block418;-因?yàn)榈谝粋€(gè)塊為塊頭,不含數(shù)據(jù),所以轉(zhuǎn)儲(chǔ)第二個(gè)塊。打開跟蹤文件以后,如下所示,可以發(fā)現(xiàn)418塊仍然是一個(gè)葉子節(jié)點(diǎn),包含10個(gè)索引條目,該索引塊還沒有被拆分。注意其中的kdxcoavs為226,說(shuō)明可用空間還剩226個(gè)字節(jié),說(shuō)明還可以插入一條記錄。之所以與前面計(jì)算
35、出來(lái)的只能放10條記錄有出入,是因?yàn)榭捎玫?623字節(jié)只是一個(gè)估計(jì)值。kdxcoavs226row#01087flag:lock:0col0;len150;(150):313061616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161
36、616161616161616161616161616161616161616161616161616161616161616161616161616161616161col1;len6;(6):01c001820004row#1926flag:,lock:0接下來(lái),我們?cè)俅尾迦胍粭l記錄,以便基本充滿該葉子節(jié)點(diǎn),使得剩下的可用空間不足以再插入一條新的條目。如下所示。SQL>insertintoindex_testvalues(rpad(to_char(11*2),150,'a');這個(gè)時(shí)候我們?cè)俅无D(zhuǎn)儲(chǔ)418塊以后會(huì)發(fā)現(xiàn)與前面轉(zhuǎn)儲(chǔ)的內(nèi)容基本一致,只是又增加了一個(gè)索引條目。而
37、這個(gè)時(shí)候,如果向表里再次插入一條新的記錄的話,該葉子節(jié)點(diǎn)(418塊)必須進(jìn)行拆分。SQL>insertintoindex_testvalues(rpad(to_char(12*2),150,'a');SQL>altersystemdumpdatafile7block418;轉(zhuǎn)儲(chǔ)出418塊以后,我們會(huì)發(fā)現(xiàn),該索引塊從葉子節(jié)點(diǎn)變成了根節(jié)點(diǎn)(kdxcolev為1,同時(shí)row#0部分的col1為TERMS示根節(jié)點(diǎn)下沒有其他分支節(jié)點(diǎn))。這也就說(shuō)明,當(dāng)?shù)谝粋€(gè)葉子節(jié)點(diǎn)充滿以后,進(jìn)行分裂時(shí),先獲得兩個(gè)可用的索引塊作為新的葉子節(jié)點(diǎn),然后將當(dāng)前該葉子節(jié)點(diǎn)里所有的索引條目拷貝到這兩個(gè)新獲
38、得的葉子節(jié)點(diǎn),最后將原來(lái)的葉子節(jié)點(diǎn)改變?yōu)楦?jié)點(diǎn)kdxcolev1,kdxbrlmc29360547=0x1c001a3,row#01909dba:29360548=0x1c001a4col0;len1;(1):34col1;TERMendofbranchblockdump同時(shí),從上面的kdxbrlmc和row#0中的dba可以知道,該根節(jié)點(diǎn)分別指向29360547和29360548兩個(gè)葉子節(jié)點(diǎn)。我們分別對(duì)這兩個(gè)葉子節(jié)點(diǎn)進(jìn)行轉(zhuǎn)儲(chǔ)看看里面放了些什么。SQL>selectdbms_utility.data_block_address_file(29360547),2dbms_utility.d
39、ata_block_address_block(29360547)fromdual;DBMS_UTILITY.DATA_BLOCK_ADDRESDBMS_UTILITY.DATA_BLOCK_ADDRES7419SQL>selectdbms_utility.data_block_address_file(29360548),2dbms_utility.data_block_address_block(29360548)fromdual;DBMS_UTILITY.DATA_BLOCK_ADDRESDBMS_UTILITY.DATA_BLOCK_ADDRES7420SQL>alters
40、ystemdumpdatafile7block419;SQL>altersystemdumpdatafile7block420;在打開跟蹤文件之前,我們先來(lái)看看表index_test里存放了哪些數(shù)據(jù)SQL>selectsubstr(id,1,2)fromindex_testorderbysubstr(id,1,2);SUBSTR(ID,1,2)10121416182022242a4a6a8a打開419塊的跟蹤文件可以發(fā)現(xiàn),里面存放了10、12、14、16、18、20、22、24和2a;而420塊的跟蹤文件中記錄了4a、6a和8a。也就是說(shuō),由于最后我們插入24的緣故,導(dǎo)致整個(gè)葉子節(jié)
41、點(diǎn)發(fā)生分裂,從而將10、12、14、16、18、20、22、和2a放至ij419塊里,而4a、6a和8a則放入420塊里。然后,再將新的索引條目(24)插入對(duì)應(yīng)的索引塊里,也就是419塊。假如我們?cè)僮詈蟛皇遣迦?2*2,而是插入9會(huì)怎么樣?我們重新測(cè)試一下,返回到index_test里有11條記錄的情況下,然后我們?cè)俨迦?。SQL>insertintoindex_testvalues(rpad('9',150,'a');這個(gè)時(shí)候,418塊還是和原來(lái)一樣變成了根節(jié)點(diǎn),同時(shí)仍然生成出了2個(gè)葉子節(jié)點(diǎn)塊,分別是419和420。但是有趣的是,419塊里的內(nèi)容與在插入
42、9之前的葉子節(jié)點(diǎn)(當(dāng)時(shí)的418塊)的內(nèi)容完全相同,而420塊里則只有一個(gè)索引條目,也就是新插入的9。這也就是說(shuō),由于最后我們插入9的緣故,導(dǎo)致整個(gè)葉子節(jié)點(diǎn)發(fā)生分裂。但是分裂過(guò)程與插入12*2的情況是不一樣的,這時(shí)該葉子節(jié)點(diǎn)的內(nèi)容不進(jìn)行拆分,而是直接完全拷貝到一個(gè)新的葉子節(jié)點(diǎn)(419)里,然后將新插入的9放入另外一個(gè)新的葉子節(jié)點(diǎn)(420)。我們應(yīng)該注意到,插入的這個(gè)9表里所有記錄里的最大字符串。如果這時(shí),我們?cè)俅尾迦?2*2,則會(huì)發(fā)現(xiàn)419號(hào)節(jié)點(diǎn)的分裂過(guò)程和前面描述的一樣,會(huì)將原來(lái)放在419塊里的4a、6a和8a放入一個(gè)新的葉子節(jié)點(diǎn)里(421塊),然后將12*2放入419塊,于是這個(gè)時(shí)候419塊
43、所含有的索引條目為10、12、14、16、18、20、22、和2a。同時(shí)420塊沒有發(fā)生變化。根據(jù)上面的測(cè)試結(jié)果,我們可以總結(jié)一下葉子節(jié)點(diǎn)的拆分過(guò)程。這個(gè)過(guò)程需要分成兩種情況,一種是插入的鍵值不是最大值;另一種是插入的鍵值是最大值。對(duì)于第一種情況來(lái)說(shuō),當(dāng)一個(gè)非最大鍵值要進(jìn)入索引,但是發(fā)現(xiàn)所應(yīng)進(jìn)入的索引塊不足以容納當(dāng)前鍵值時(shí):從索引可用列表上獲得一個(gè)新的索引數(shù)據(jù)塊。將當(dāng)前充滿了的索引中的索引條目分成兩部分,一部分是具有較小鍵值的,另一部分是具有較大鍵值的。Oracle會(huì)將具有較大鍵值的部分移入新的索引數(shù)據(jù)塊,而較小鍵值的部分保持不動(dòng)。將當(dāng)前鍵值插入合適的索引塊中,可能是原來(lái)空間不足的索引塊,也可
44、能是新的索引塊。更新原來(lái)空間不足的索引塊的kdxlenxt信息,使其指向新的索引塊。更新位于原來(lái)空間不足的索引塊右邊的索引塊里的kdxleprv,使其指向新的索引塊。向原來(lái)空間不足的索引塊的上一級(jí)的分支索引塊中添加一個(gè)索引條目,該索引條目中保存新的索引塊里的最小鍵值,以及新的索引塊的地址。從上面有關(guān)葉子節(jié)點(diǎn)分裂的過(guò)程可以看出,其過(guò)程是非常復(fù)雜的。因此如果發(fā)生的是第二種情況,則為了簡(jiǎn)化該分裂過(guò)程,oracle省略了上面的第二步,而是直接進(jìn)入第三步,將新的鍵值插入新的索引塊中。在上例中,當(dāng)葉子節(jié)點(diǎn)越來(lái)越多,導(dǎo)致原來(lái)的根節(jié)點(diǎn)不足以存放新的索引條目(這些索引條目指向葉子節(jié)點(diǎn))時(shí),則該根節(jié)點(diǎn)必須進(jìn)行分裂
45、。當(dāng)根節(jié)點(diǎn)進(jìn)行分裂時(shí):從索引可用列表上獲得兩個(gè)新的索引數(shù)據(jù)塊。將根節(jié)點(diǎn)中的索引條目分成兩部分,這兩部分分別放入兩個(gè)新的索引塊,從而形成兩個(gè)新的分支節(jié)點(diǎn)。更新原來(lái)的根節(jié)點(diǎn)的索引條目,使其分別指向這兩個(gè)新的索引塊。因此,這時(shí)的索引層次就變成了2層。同時(shí)可以看出,根節(jié)點(diǎn)索引塊在物理上始終都是同一個(gè)索引塊。而隨著數(shù)據(jù)量的不斷增加,導(dǎo)致分支節(jié)點(diǎn)又要進(jìn)行分裂。分支節(jié)點(diǎn)的分裂過(guò)程與根節(jié)點(diǎn)類似(實(shí)際上根節(jié)點(diǎn)分裂其實(shí)是分支節(jié)點(diǎn)分裂的一個(gè)特例而已):從索引可用列表上獲得一個(gè)新的索引數(shù)據(jù)塊。將當(dāng)前滿了的分支節(jié)點(diǎn)里的索引條目分成兩部分,較小鍵值的部分不動(dòng),而較大鍵值的部分移入新的索引塊。將新的索引條目插入合適的分支索
46、引塊。在上層分支索引塊中添加一個(gè)新的索引條目,使其指向新加的分支索引塊。當(dāng)數(shù)據(jù)量再次不斷增加,導(dǎo)致原來(lái)的根節(jié)點(diǎn)不足以存放新的索引條目(這些索引條目指向分支節(jié)點(diǎn))時(shí),再次引起根節(jié)點(diǎn)的分裂,其分裂過(guò)程與前面所說(shuō)的由于葉子節(jié)點(diǎn)的增加而導(dǎo)致的根節(jié)點(diǎn)分裂的過(guò)程是一樣的。同時(shí),根節(jié)點(diǎn)分裂以后,索引的層級(jí)再次遞增。由此可以看出,根據(jù)B樹索引的分裂機(jī)制,一個(gè)B樹索引始終都是平衡的。注意,這里的平衡是指每個(gè)葉子節(jié)點(diǎn)與根節(jié)點(diǎn)的距離都是相同的。同時(shí),從索引的分裂機(jī)制可以看出,當(dāng)插入的鍵值始終都是增大的時(shí)候,索引總是向右擴(kuò)展;而當(dāng)插入的鍵值始終都是減小的時(shí)候,索引則總是向左擴(kuò)展。深入研究B樹索引(五)2010-03-
47、2501:485.重建B樹索引5.1 如何重建B樹索引重建索引有兩種方法:一種是最簡(jiǎn)單的,刪除原索引,然后重建;第二種是使用ALTERINDEX,REBUILD命令對(duì)索引進(jìn)行重建。第二種方式是從oracle7.3.3版本開始引入的,從而使得用戶在重建索引時(shí)不必刪除原索引再重新CREATEINDEX0ALTERINDEX,REBUILDS寸CREATEINDEX以下好處:2 !-if!supportLists->1)<!-endif->它使用原索引的葉子節(jié)點(diǎn)作為新索引的數(shù)據(jù)來(lái)源。我們知道,原索引的葉子節(jié)點(diǎn)的數(shù)據(jù)塊通常都要比表里的數(shù)據(jù)塊要少很多,因此進(jìn)行的I/O就會(huì)減少;同時(shí),由
48、于原索引的葉子節(jié)點(diǎn)里的索引條目已經(jīng)排序了,因此在重建索引的過(guò)程中,所做的排序工作也要少的多。3 !-if!supportLists->2)<!-endif->自從oracle8.1.6以來(lái),ALTERINDEX,REBUILD命令可以添加ONLINE®語(yǔ)。這使得在重建索引的過(guò)程中,用戶可以繼續(xù)對(duì)原來(lái)的索引進(jìn)行修改,也就是說(shuō)可以繼續(xù)對(duì)表進(jìn)行DMLB作。而同時(shí),ALTERINDEX,REBUILD與CREATEINDEX有很多相同之處:4 !-if!supportLists->1)<!-endif->它們都可以通過(guò)添加PARALLEL提示進(jìn)行并行處理。
49、5 !-if!supportLists->2)<!-endif->它們都可以通過(guò)添加NOLOGGING短語(yǔ),使得重建索引的過(guò)程中產(chǎn)生最少的重做條目(redoentry)。<!-if!supportLists->3)<!-endif->自從oracle8.1.5以來(lái),它們都可以田間COMPUTESTATISTICS語(yǔ),從而在重建索引的過(guò)程中,就生成CBO所需要的統(tǒng)計(jì)信息,這樣就避免了索引創(chuàng)建完畢以后再次運(yùn)行analyze或dbms_stats來(lái)收集統(tǒng)計(jì)信息。當(dāng)我們重建索引以后,在物理上所能獲得的好處就是能夠減少索引所占的空間大小(特別是能夠減少葉子節(jié)點(diǎn)的
50、數(shù)量)。而索引大小減小以后,又能帶來(lái)以下若干好處:<!-if!supportLists->1)<!-endif->CBO對(duì)于索引的使用可能會(huì)產(chǎn)生一個(gè)較小的成本值,從而在執(zhí)行計(jì)劃中選擇使用索引。<!-if!supportLists->2)<!-endif->使用索引掃描的查詢掃描的物理索引塊會(huì)減少,從而提高效率。<!-if!supportLists->3)<!-endif->由于需要緩存的索引塊減少了,從而讓出了內(nèi)存以供其他組件使用。盡管重建索引具有一定的好處,但是盲目的認(rèn)為重建索引能夠解決很多問(wèn)題也是不正確的。比如我見過(guò)一
51、個(gè)生產(chǎn)系統(tǒng),每隔一個(gè)月就要重建所有的索引(而且我相信,很多生產(chǎn)系統(tǒng)可能都會(huì)這么做),其中包括一些100GB的大表。為了完成重建所有的索引,往往需要把這些工作分散到多個(gè)晚上進(jìn)行。事實(shí)上,這是一個(gè)7X24的系統(tǒng),僅重建索如果索引的層級(jí)超過(guò)X(X通常如果經(jīng)常刪除索引鍵值,則需如果索弓I的clustering_factor引一項(xiàng)任務(wù)就消耗了非常多的系統(tǒng)資源。但是每隔一段時(shí)間就重建索引有意義嗎?這里就有一些關(guān)于重建索引的很流行的說(shuō)法,主要包括:<!-if!supportLists->1)<!-endif->是3)級(jí)以后需要通過(guò)重建索引來(lái)降低其級(jí)別。<!-if!support
52、Lists->2)<!-endif->要定時(shí)重建索引來(lái)收回這些被刪除的空間。<!-if!supportLists->3)<!-endif->很高,則需要重建索引來(lái)降低該值。<!-if!supportLists->4<!-endif->定期重建索引能夠提高性能。對(duì)于第一點(diǎn)來(lái)說(shuō),我們?cè)谇懊嬉呀?jīng)知道,B樹索引是一棵在高度上平衡的樹,所以重建索引基本不可能降低其級(jí)別,除非是極特殊的情況導(dǎo)致該索引有非常大量的碎片,導(dǎo)致B樹索引“虛高”,那么這實(shí)際又來(lái)到第二點(diǎn)上(因?yàn)樗槠ǔ6际怯捎趧h除引起的)。實(shí)際上,對(duì)于第一和第二點(diǎn),我們應(yīng)該通過(guò)運(yùn)行A
53、LTERINDEX,REBUILD命令以后檢查indest_stats.pct_used字段來(lái)判斷是否有必要重建索引。5.2重建B樹索引對(duì)于clustering_factor的影響而對(duì)于clustering_factor來(lái)說(shuō),它是用來(lái)比較索引的順序程度與表的雜亂排序程度的一個(gè)度量。Oracle在計(jì)算某個(gè)clustering_factor時(shí),會(huì)對(duì)每個(gè)索引鍵值查找對(duì)應(yīng)到表的數(shù)據(jù),在查找的過(guò)程中,會(huì)跟位從一個(gè)表的數(shù)據(jù)塊跳轉(zhuǎn)到另外一個(gè)數(shù)據(jù)塊的次數(shù)(當(dāng)然,它不可能真的這么做,源代碼里只是簡(jiǎn)單的掃描索引,從而獲得ROWID然后從這些ROWI威得表的數(shù)據(jù)塊的地址)。每一次跳轉(zhuǎn)時(shí),有個(gè)計(jì)數(shù)器就會(huì)增加,最終該計(jì)
54、數(shù)器的值就是clustering_factor。下圖四描述了這個(gè)原理。200R4300R5曳如700Ri27P0RI3償RI4S10R1;mRLE儂R?鋼R8JD0R9600P.1069CJR.111005R17_12001200RIPORI29R21WR3尊3940350070D79:3i0goQIQ0512001300圖四在上圖四中,我們有一個(gè)表,該表有4個(gè)數(shù)據(jù)塊,以及20條記錄。在列N1上有一個(gè)索引,上圖中的每個(gè)小黑點(diǎn)就表示一個(gè)索引條目。列N1的值如圖所示。而N1的索引的葉子節(jié)點(diǎn)包含的值為:A、B、C、DE、F。如果oracle開始掃描索引的底部,葉子節(jié)點(diǎn)包含的第一個(gè)N1值為A,那么根據(jù)
55、該值可以知道對(duì)應(yīng)的ROWI現(xiàn)于第一個(gè)數(shù)據(jù)塊的第三行里,所以我們的計(jì)數(shù)器增加1。同時(shí),A值還對(duì)應(yīng)第二個(gè)數(shù)據(jù)塊的第四行,由于跳轉(zhuǎn)到了不同的數(shù)據(jù)塊上,所以計(jì)數(shù)器再加1。同樣的,在處理B時(shí),可以知道對(duì)應(yīng)第一個(gè)數(shù)據(jù)塊的第二行,由于我們從第二個(gè)數(shù)據(jù)塊跳轉(zhuǎn)到了第一個(gè)數(shù)據(jù)塊,所以計(jì)數(shù)器再加1。同時(shí),B值還對(duì)應(yīng)了第一個(gè)數(shù)據(jù)塊的第五行,由于我們這里沒有發(fā)生跳轉(zhuǎn),所以計(jì)數(shù)器不用加1。在上面的圖里,在表的每一行的下面都放了一個(gè)數(shù)字,它用來(lái)顯示計(jì)數(shù)器跳轉(zhuǎn)到該行時(shí)對(duì)應(yīng)的值。當(dāng)我們處理完索引的最后一個(gè)值時(shí),我們?cè)跀?shù)據(jù)塊上一共跳轉(zhuǎn)了十次,所以該索引的clustering_factor為10。注意第二個(gè)數(shù)據(jù)塊,clusteri
56、ng_factor為8出現(xiàn)了4次。因?yàn)樵谒饕颪1為E所對(duì)應(yīng)的4個(gè)索引條目都指向了同一個(gè)數(shù)據(jù)塊。從而使得clustering_factor不再增長(zhǎng)。同樣的現(xiàn)象出現(xiàn)在第三個(gè)數(shù)據(jù)塊中,它包含三條記錄,它們的值都是C,對(duì)應(yīng)的clustering_factor都是6。從clustering_factor的計(jì)算方法上可以看出,我們可以知道它的最小值就等于表所含有的反據(jù)塊的數(shù)量;而最大值就是表所含有的記錄的總行數(shù)。很明顯,clustering_factor越小越好,越小說(shuō)明通過(guò)索引查找表里的數(shù)據(jù)行時(shí)需要訪問(wèn)的表的數(shù)據(jù)塊越少我們來(lái)看一個(gè)例子,來(lái)說(shuō)明重建索引對(duì)于減小clustering_factor沒有用處。
57、首先我們創(chuàng)建一個(gè)測(cè)試表:SQL>createtableclustfact_test(idnumber,namevarchar2(10);SQL>createindexidx_clustfact_testonclustfact_test(id);然后,我們插入十萬(wàn)條記錄。SQL>begin2 foriin1.100000loop3 insertintoclustfact_testvalues(mod(i,200),to_char(i);4 endloop;5 commit;6 end;7 /因?yàn)槭褂昧薽od的關(guān)系,最終數(shù)據(jù)在表里排列的形式為:0,1,2,3,4,5,197,198,199,0,1,2,3,197,198,199,0,1,2,3,197,198,199,0,1,2,3,接下來(lái),我們分析表。SQL>execdbms_stats.gather_t
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 救災(zāi)物資保障與配送實(shí)施方案
- 供電工程瓦工施工合同范本
- 礦山磨礦設(shè)備租賃合同
- 招投標(biāo)文件應(yīng)急預(yù)案評(píng)審記錄表
- 五金元訂購(gòu)合同
- 2024廢舊金屬買賣的合同范本
- 旅游公司醫(yī)療救援人員合同模板
- 員工福利優(yōu)化:全新休假管理辦法
- 農(nóng)村留守兒童教育
- 醫(yī)院建筑內(nèi)外墻抹灰專項(xiàng)方案
- Integrated skills 【基礎(chǔ)梳理+隨堂演練】 高一英語(yǔ)精講課件(譯林版2020必修第二冊(cè))
- 爆破作業(yè)單位安全檢查
- 作文技巧:中心明確上課(余映潮板塊式)復(fù)習(xí)進(jìn)程
- 維生素D教學(xué)講解課件
- 《寒號(hào)鳥》-教學(xué)講解課件
- 潔凈廠房監(jiān)理實(shí)施細(xì)則
- 《數(shù)列》高中數(shù)學(xué)課件
- 《突發(fā)事件應(yīng)對(duì)法》考試題庫(kù)(附答案)
- 水火箭的制作發(fā)射課件
- 北師大版高二英語(yǔ)新教材選擇性必修二課文及翻譯(中英文Word)
- 歐盟GMP培訓(xùn)課件
評(píng)論
0/150
提交評(píng)論