【正文】
在后面的敘述中,我們將會(huì)使用”row source”來代替”表”,因?yàn)槭褂胷ow source更嚴(yán)謹(jǐn)一些,并且將參與連接的2個(gè)row source分別稱為row source1和row source 2。 INDEX FAST FULL SCAN BE_IX [ANALYZED]只選擇多列索引的第2列:SQL explain plan for select ename from big_emp。[CHOOSE] Cost=1Query PlanSELECT STATEMENT在這種存取方法中,可以使用多塊讀功能,也可以使用并行讀入,以便獲得最大吞吐量與縮短執(zhí)行時(shí)間。 INDEX FULL SCAN BE_IX [ANALYZED][CHOOSE] Cost=26Query PlanSELECT STATEMENTs and so it may prove to be inefficient(低效的,因?yàn)槭嵌鄩K,所以可能會(huì)讀取用不到的數(shù)據(jù)塊,導(dǎo)致做無用功!但是索引全掃描不是單塊讀取么,怎么說不會(huì)進(jìn)行單塊讀取呢?).CBO根據(jù)統(tǒng)計(jì)數(shù)值得知進(jìn)行全索引掃描比進(jìn)行全表掃描更有效時(shí),才進(jìn)行全索引掃描,而且此時(shí)查詢出的數(shù)據(jù)都必須從索引中可以直接得到。 與全表掃描對(duì)應(yīng),也有相應(yīng)的全索引掃描。 (3) 索引全掃描(index full scan) 在非唯一索引上,謂詞col = 5可能返回多行數(shù)據(jù),所以在非唯一索引上都使用索引范圍掃描。 INDEX RANGE SCAN EMP_I1 [ANALYZED] 使用索引范圍掃描的例子:SQL explain plan for select empno,ename from empwhere empno 7876 order by empno。 在唯一索引上使用索引范圍掃描的典型情況下是在謂詞(where限制條件)中使用了范圍操作符(如、=、=、between) TABLE ACCESS BY ROWID EMP [ANALYZED] SELECT STATEMENT [CHOOSE] Cost=1 Query Plan 如果存在UNIQUE 或PRIMARY KEY 約束(它保證了語句只存取單行)的話,Oracle經(jīng)常實(shí)現(xiàn)唯一性掃描。如果該語句只返回一行,則存取方法稱為索引唯一掃描。如果該唯一索引有多個(gè)列組成(即組合索引),則至少要有組合索引的引導(dǎo)列參與到該查詢中,如創(chuàng)建一個(gè)索引:create index idx_test on emp(ename, deptno, loc)。 從這個(gè)例子中可以看到:因?yàn)樗饕且呀?jīng)排序了的,所以將按照索引的順序查詢出符合條件的行,因此避免了進(jìn)一步排序操作。 TABLE ACCESS BY ROWID EMP [ANALYZED][CHOOSE] Cost=1Query PlanSELECT STATEMENT SQL explain plan for select empno from emp where empno=10。(不太懂)。而沒有使用select count() from SWD_BILLDETAIL where 39。所以上面我在介紹基于規(guī)則的優(yōu)化器時(shí),使用了select count(id) from SWD_BILLDETAIL where 39。 在此例中,所需要的rowid是由于在索引查找empno列的值得到的,這種方式是INDEX UNIQUE SCAN查找,后面給予介紹,EMP_I1為使用的進(jìn)行索引查找的索引名字。 Query PlanSELECT STATEMENT [CHOOSE] Cost=1TABLE ACCESS BY ROWID EMP [ANALYZED]所以如果多大表進(jìn)行索引掃描,取出的數(shù)據(jù)如果大于總量的5% 10%,使用索引掃描會(huì)效率下降很多(因?yàn)橐獑螇K讀取)。每步都是單獨(dú)的一次I/O,但是對(duì)于索引,由于經(jīng)常使用,絕大多數(shù)都已經(jīng)CACHE到內(nèi)存中,所以第1步的I/O經(jīng)常是邏輯I/O,即數(shù)據(jù)可以從內(nèi)存中得到。索引掃描可以由2步組成:(1) 掃描索引得到對(duì)應(yīng)的rowid值。 一個(gè)rowid唯一的表示一行數(shù)據(jù),該行對(duì)應(yīng)的數(shù)據(jù)塊是通過一次i/o得到的,在此情況下該次i/o只會(huì)讀取一個(gè)數(shù)據(jù)庫塊。 AAAAyGAADAAAAATAAF39。我們會(huì)經(jīng)常在執(zhí)行計(jì)劃中看到該存取方法,如通過索引查詢數(shù)據(jù)。 Oracle然后以得到的ROWID為依據(jù)定位每個(gè)被選擇的行。 行的ROWID指出了該行所在的數(shù)據(jù)文件、數(shù)據(jù)塊以及行在該塊中的位置,所以通過ROWID來存取數(shù)據(jù)可以快速定位到目標(biāo)數(shù)據(jù)上,是Oracle存取單行數(shù)據(jù)的最快方法。TABLE ACCESS FULL DUAL2) 通過ROWID的表存?。═able Access by ROWID或rowid lookup) [CHOOSE] Cost= SELECT STATEMENT Query Plan 使用FTS的前提條件:在較大的表上不建議使用全表掃描,除非取出數(shù)據(jù)的比較多,超過總量的5% 10%,或你想使用并行查詢功能時(shí)。 幸運(yùn)的是oracle 10G后,可以人工收縮HWM的值。在這種訪問模式下,每個(gè)數(shù)據(jù)塊只被讀一次。Oracle順序地讀取分配給表的每個(gè)數(shù)據(jù)塊,直到讀到表的最高水線處(high water mark, HWM,標(biāo)識(shí)表的最后一個(gè)數(shù)據(jù)塊)。 在物理層,oracle讀取數(shù)據(jù),一次讀取的最小單位為數(shù)據(jù)庫塊(由多個(gè)連續(xù)的操作系統(tǒng)塊組成),一次讀取的最大值由操作系統(tǒng)一次I/O的最大值與multiblock參數(shù)共同決定,所以即使只需要一行數(shù)據(jù),也是將該行所在的數(shù)據(jù)庫塊讀入內(nèi)存。 對(duì)于SQL語句存取的任何表中的任何行,可能存在許多存取路徑(存取方法),通過它們可以定位和查詢出需要的數(shù)據(jù)。 現(xiàn)在先來看一些預(yù)備知識(shí)。有時(shí)語句執(zhí)行時(shí),并不是象上面說的那樣一步一步有先有后的進(jìn)行,而是可能并行運(yùn)行,如在實(shí)際環(huán)境中,4步可能并行運(yùn)行,以便取得更好的效率。這樣的父步驟包括排序,排序一合并的連接,組功能和總計(jì)。有些父步驟在它們被實(shí)現(xiàn)之前需要來自子步驟的所有行。對(duì)每個(gè)由子步驟依次檢索出來的每一行,Oracle就實(shí)現(xiàn)父步驟及所有串聯(lián)在一起的步驟一次。所以,執(zhí)行可以在樹上串聯(lián)上去,可能包含執(zhí)行計(jì)劃的余下部分。對(duì)這樣的父步驟來說,只要從子步驟已返回單一行時(shí)立即實(shí)現(xiàn)父步驟(可能還有執(zhí)行計(jì)劃的其余部分)。 注意Oracle對(duì)由第3步返回的每一行實(shí)現(xiàn)步驟5,4,2,6一次。 Oracle實(shí)現(xiàn)步驟6,如果有結(jié)果行的話,將它返回給第1步。 Oracle實(shí)現(xiàn)步驟4,并將結(jié)果行返回給第2步。 首先,Oracle實(shí)現(xiàn)步驟3,并一行一行地將結(jié)果行返回給第2步。 舉例來說,為了執(zhí)行圖51中的語句,Oracle以下列順序?qū)崿F(xiàn)這些步驟:l由每一步返回的行稱為它下一步驟的行源。它接收來自第2步和第6步的行源,消除掉第2步中來的,在第6步有相應(yīng)行的那些行,并將來自第2步的剩下的行返回給發(fā)出語句的用戶或應(yīng)用。 第2步實(shí)現(xiàn)嵌套的循環(huán)操作(相當(dāng)于C語句中的嵌套循環(huán)),接收從第3步和第4步來的行源,把來自第3步源的每一行與它第4步中相應(yīng)的行連接在一起,返回結(jié)果行到第1步。 由黑色字框指出的步驟在行源上操作,如做2表之間的關(guān)聯(lián),排序,或過濾等操作,后面也會(huì)給出詳細(xì)的介紹:l 它找出與DEPT表中相關(guān)聯(lián)的那些行的ROWID。 第3步和第6步分別的從EMP表和SALGRADE表讀所有的行。 這種步驟被稱之為存取路徑,后面會(huì)詳細(xì)介紹在Oracle可以使用的存取路徑:l一般來說這并不是每一步被執(zhí)行的先后順序。圖51樹狀圖顯示了從一步到另一步行數(shù)據(jù)的流動(dòng)情況。執(zhí)行計(jì)劃的每一步返回一組行,它們或者為下一步所使用,或者在最后一步時(shí)返回給發(fā)出SQL語句的用戶或應(yīng)用。下圖51顯示了一個(gè)執(zhí)行計(jì)劃的圖形表示:執(zhí)行計(jì)劃的步驟 FROM salgradeWHERE BETWEEN losal AND hisal )。 舉例:這個(gè)例子顯示關(guān)于下面SQL語句的執(zhí)行計(jì)劃。 下面先從分析樹型執(zhí)行計(jì)劃開始介紹,然后介紹如何得到執(zhí)行計(jì)劃,再介紹如何分析執(zhí)行計(jì)劃。執(zhí)行計(jì)劃對(duì)于DBA來說,就象財(cái)務(wù)報(bào)表對(duì)于財(cái)務(wù)人員一樣重要。Oracle用來執(zhí)行語句的這些步驟的組合被稱之為執(zhí)行計(jì)劃。為了執(zhí)行語句,Oracle可能必須實(shí)現(xiàn)許多步驟。 在可選擇性高的列上進(jìn)行查詢時(shí),返回的數(shù)據(jù)就較少,比較適合使用索引查詢。 比較一下列中唯一鍵的數(shù)量和表中的行數(shù),就可以判斷該列的可選擇性。 可選擇性(selectivity):當(dāng)我們進(jìn)行查詢時(shí)可以使用”where col1 = ? ”,也可以使用”where col1 = ? and col2 = ?”,這樣的限制條件都會(huì)使用索引,但是”where col2 = ? ”查詢就不會(huì)使用該索引。 由多個(gè)列構(gòu)成的索引,如create index idx_emp on emp(col1, col2, col3, ……),則我們稱idx_emp索引為組合索引。 組合索引(concatenated index)所以該表應(yīng)當(dāng)為大表(實(shí)際上應(yīng)該為返回較大row source的表)且相應(yīng)的列上應(yīng)該有索引。 該表又稱為內(nèi)層表(INNER TABLE)。 Probed Table(被探查表)在執(zhí)行計(jì)劃中,應(yīng)該為靠上的那個(gè)row source,后面會(huì)給出具體說明。注意此處雖然翻譯為驅(qū)動(dòng)表,但實(shí)際上翻譯為驅(qū)動(dòng)行源(driving row source)更為確切。這個(gè)概念用于嵌套與HASH連接中。 用在查詢中,由上一操作返回的符合條件的行的集合,即可以是表的全部行數(shù)據(jù)的集合;也可以是表的部分行數(shù)據(jù)的集合;也可以為對(duì)上2個(gè)row source進(jìn)行連接操作(如join連接)后得到的行數(shù)據(jù)集合。 Row Source(行源)當(dāng)然DML語句與SELECT都可能引起recursive SQL。當(dāng)需要的數(shù)據(jù)字典信息沒有在共享內(nèi)存中時(shí),經(jīng)常會(huì)發(fā)生Recursive calls,這些Recursive calls會(huì)將數(shù)據(jù)字典信息從硬盤讀入內(nèi)存中。recursive SQL statements39。recursive calls39。 利用DBMS_ROWID可以將rowid分解成上述的各部分,也可以將上述的各部分組成一個(gè)有效的rowid。 在ORACLE8以前的版本中,ROWID由FILE 、BLOCK、ROW NUMBER構(gòu)成。我們創(chuàng)建一個(gè)索引時(shí),該索引不但存儲(chǔ)索引列的值,而且也存儲(chǔ)索引值所對(duì)應(yīng)的行的ROWID,這樣我們通過索引快速找到相應(yīng)行的ROWID后,通過該ROWID,就可以迅速將數(shù)據(jù)查詢出來。 一旦一行數(shù)據(jù)插入數(shù)據(jù)庫,則rowid在該行的生命周期內(nèi)是唯一的,即即使該行產(chǎn)生行遷移,行的rowid也不會(huì)改變。對(duì)每個(gè)表都有一個(gè)rowid的偽列,但是表中并不物理存儲(chǔ)ROWID列的值。 所以建議編寫需要穩(wěn)定運(yùn)行程序的開發(fā)人員最好還是一開始就使用綁定變量的SQL。因?yàn)橛锌赡茉撟冊(cè)撝岛?,你的硬編碼SQL是可以使用共享SQL了,但數(shù)據(jù)庫的性能反而會(huì)下降。聽起來不錯(cuò),ORACLE真為用戶著想,使用戶在不改變代碼的情況下還可以利用共享SQL的功能。 上面的代碼實(shí)際上使用了硬編碼SQL,使我們不能使用共享SQL的功能,結(jié)果是數(shù)據(jù)庫效率不高。 …………int_empno = 1000。int_empno = 2000。因?yàn)樵趯?shí)際開發(fā)中,很多程序人員為了提高開發(fā)速度,而采用類似下面的開發(fā)方法:str_sql string。 而直接執(zhí)行該語句,提高了執(zhí)行效率,因?yàn)檎Z法分析比較耗費(fèi)資源。 4). 在SQL語句中使用的捆綁變量的捆綁類型(捆綁類型是什么意思?)必須一致。 因?yàn)閮蓚€(gè)語句中引用的EMP不是指同一個(gè)表。 用戶user2發(fā)出的語句:SELECT * FROM EMP。 與 例如: 今后我們將上面的這類語句稱為綁定變量SQL。 select pin , name from people where pin = :。 select pin , name from people where pin = :。 b. 該2個(gè)sql語句被認(rèn)為不相同 select pin , name from people where pin = :。 select pin , name from