對于優(yōu)化器而言,它在解析目標(biāo)SQL,得到執(zhí)行計(jì)劃時(shí)至關(guān)重要的一點(diǎn)是決定訪問數(shù)據(jù)的方法,即優(yōu)化器要決定采用什么樣的方式和方法去訪問目標(biāo)SQL所需要訪問的存儲在oracle數(shù)據(jù)庫中的數(shù)據(jù)。
目前成都創(chuàng)新互聯(lián)公司已為上千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁空間、網(wǎng)站托管維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、綏德網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
目標(biāo)SQL所需要訪問的數(shù)據(jù)一般存儲在表里,而oracle訪問表中數(shù)據(jù)的方法有兩種:一種直接訪問表,另一種是先訪問索引,在回表(當(dāng)然,如果目標(biāo)sql所要訪問的數(shù)據(jù)只通過訪問相關(guān)的索引就可以得到,那么此時(shí)就不需要回表了)
oracle數(shù)據(jù)庫中直接方位表中數(shù)據(jù)的方法有兩種:一是全表掃描,而是rowid掃描
1. 全表掃描
全掃描時(shí)指oracle在訪問目標(biāo)表里數(shù)據(jù)時(shí),會(huì)從該表所占用的第一個(gè)區(qū)(EXTENT)的第一個(gè)塊(BLOCK)開始掃描,一直掃描到該表的高水位線(HWM),這段范圍內(nèi)所有的數(shù)據(jù)塊oracle都必須讀到。當(dāng)然oracle會(huì)對這期間讀到的所有數(shù)據(jù)施加目標(biāo)SQL的where條件中指定的條件,最后只返回那些滿足過濾條件的數(shù)據(jù)。
不是全表掃描不好,事實(shí)上oracle在做全表掃描操作時(shí)會(huì)使用多塊讀,這在目標(biāo)表的數(shù)據(jù)量不大時(shí)執(zhí)行效率是非常高的,但全表掃描最大問題就在于走全表掃描的目標(biāo)sql的執(zhí)行時(shí)間不穩(wěn)定,不可控,這個(gè)執(zhí)行時(shí)間一定會(huì)隨著目標(biāo)表數(shù)據(jù)量的遞增而遞增。因?yàn)殡S著目標(biāo)表數(shù)據(jù)量的遞增,它的高水位線會(huì)一直不斷上漲,所以全表掃描該表時(shí)所需要讀取的數(shù)據(jù)塊的數(shù)量也不斷增加,這意味著全表掃描該表時(shí)所需要耗費(fèi)的I/O資源隨之不斷增加,當(dāng)然完成對該表的全掃描所需要耗費(fèi)的時(shí)間也會(huì)隨之增加。另外,對于CBO而言,所要耗費(fèi)I/O資源不斷增加意味著全表掃描的成本值也會(huì)隨著目標(biāo)表數(shù)據(jù)量的遞增而遞增。
在oracle中,如果對目標(biāo)表不停地插入數(shù)據(jù),當(dāng)分配給該表的現(xiàn)有空間不足時(shí)高水位線就會(huì)向上移動(dòng),但如果你用delete語句從該表中刪除數(shù)據(jù),則高水位線并不會(huì)隨之往下移動(dòng)。高水位線的這種特性帶來的負(fù)作用是,即使使用delete語句刪除所有數(shù)據(jù),高水位線還是再原來的位置,這意味這個(gè)全表掃描該表時(shí)還是需要掃描該表高水位線下的所有數(shù)據(jù)塊,所以此時(shí)對該表的全表掃描操作所耗費(fèi)的時(shí)間與之前相比不會(huì)有明細(xì)的改善。
2.ROWID掃描
ROWID掃描是指oracle在訪問目標(biāo)表里的數(shù)據(jù)時(shí),直接通過數(shù)據(jù)所在的rowid去定位并訪問這些數(shù)據(jù)。rowid表示的是oracle的數(shù)據(jù)行記錄所在物理存儲地址,也就是說rowid實(shí)際上是和oracle中數(shù)據(jù)塊里的行記錄一一對應(yīng)的。
既然rowid代表的就是表的數(shù)據(jù)行所在的物理存儲地址,那么當(dāng)oracle知道待訪問的數(shù)據(jù)行所在rowid后,自然就可以根據(jù)rowid去直接訪問對應(yīng)表的相關(guān)數(shù)據(jù)行,這就是rowid的定義。
從嚴(yán)格意思來說,oracle中rowid掃描有兩層含義:一種是根據(jù)用戶在sql語句中輸入rowid的值直接訪問對應(yīng)的數(shù)據(jù)行記錄;另一種是先去訪問相關(guān)的索引,然后根據(jù)訪問索引后得到的rowid再回表去訪問對應(yīng)的行記錄。
對oralce中堆表而言,我們可以通過內(nèi)置的rowid偽劣得到對應(yīng)行記錄所在的rowid的值(注意,這個(gè)rowid只是一個(gè)偽劣,在實(shí)際的表塊中并不存在該列)然后我們可以通過dbms_rowid包中的相關(guān)方法(dbms_rowid.rowid_relative_fno,dbms_rowid.rowid_block_number和dbms_rowid.rowid_row_number)將上述偽列的值翻譯成對應(yīng)數(shù)據(jù)行的實(shí)際物理存儲地址。
SQL> select empno,ename,rowid,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid)||'_'||dbms_rowid.rowid_row_number(rowid) location from emp;
EMPNO ENAME ROWID LOCATION
---------- ---------- ------------------ --------------------------------------------------
7369 SMITH AAAVREAAEAAAACXAAA 4_151_0
14 rows selected.
從上述顯示內(nèi)容可以看出,empno為7369的行記錄所對應(yīng)的rowid偽列的值為“AAAVREAAEAAAACXAAA ”,使用dbms_rowid包對該列翻譯后的值為4_151_0,這表是empno為7369的行記錄實(shí)際的物理存儲地址位于4號文件第151個(gè)數(shù)據(jù)塊的第0行記錄(數(shù)據(jù)塊里數(shù)據(jù)行記錄的記錄號從0開始算起)
上述rowid偽列的值是可以直接在sql語句中where條件中使用的,這就是oralce中rowid掃描的兩層含義中第一種,根據(jù)用戶在sql語句中輸入的rowid的值直接去訪問數(shù)據(jù)行記錄。
SQL> select empno,ename from emp where rowid='AAAVREAAEAAAACXAAL';
EMPNO ENAME
---------- ----------
7900 JAMES