CBO:評估 I/O,CPU,網絡(DBLINK)等消耗的資源成本得出html
cardinality:集合中包含的記錄數。實際CBO評估目標SQL執行具體步驟的記錄數,cardinality和成本是相關的,cardinality越大,執行步驟中的成本就越大sql
Selectivity :謂詞的過濾條件返回的結果的行數佔未加謂詞過濾條件的行數數據庫
範圍0-1,值越小,說明 選擇性越好 返回的cardinality 越小;值越大,選擇性越差,返回的cardinality 越大。網絡
未加任何謂詞條件結果集: original cardinality,增長謂詞條件爲:computed cardinality。oracle
computed cardinality=original cardinality*selectivityoop
在列上沒有NULL或者直方圖的狀況下,selectivity取值優化
NUM_DISTINCT :表示爲列中不一樣值的個數code
CBO會對現有的sql語句作等價轉換,謂詞條件、字段鏈接
優化器基礎概念
(一)、RBO
RBO基於規則的優化器access paths優先級:
注意在不違反如上優先級的前提下,如有2個優化級同樣的索引可用,則RBO會選擇晚建的那個索引, 解決方法是重建你想要讓RBO使用的那個索引,或者使用CBO……..
(二)、optimizer_mode :優化器的模式
一、RULE:使用rbo的規則
二、CHOOSE:9i中默認值,SQL語句所有的對象中無統計信息,使用RBO,其餘使用CBO
三、FIRST_ROWS_n(n=1,10,100,1000):CBO會把哪些可以最快響應速度返回的成本設置爲很小的值
四、ALL_ROWS:oracle10g 之後的默認值,會使用CBO來解析SQL,計算各個執行路徑中的成本值最佳的吞吐量(最小的I/O和CPU資源)
2、結果集
執行計劃中row,CBO評估的cardinality
3、訪問數據的方法
(一)、訪問表的方法:全表掃描和rowid訪問
全表掃描:從高水位線下所有數據塊讀取,DELETE不會降低高水位線
ROWID訪問:經過物理存儲地址直接訪問,rowid是個僞列,可是他能快速的定位的數據文件、塊、行
scott@GULL> select empno,rowid ,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid)||'_'||dbms_rowid.rowid_row_number(rowid) location_row from emp; EMPNO ROWID LOCATION_ROW ---------- ------------------ ------------------------------ 7369 AAASZHAAEAAAACXAAA 4_151_0 7499 AAASZHAAEAAAACXAAB 4_151_1 7521 AAASZHAAEAAAACXAAC 4_151_2 7566 AAASZHAAEAAAACXAAD 4_151_3 7654 AAASZHAAEAAAACXAAE 4_151_4 7698 AAASZHAAEAAAACXAAF 4_151_5 7782 AAASZHAAEAAAACXAAG 4_151_6 7788 AAASZHAAEAAAACXAAH 4_151_7 7839 AAASZHAAEAAAACXAAI 4_151_8 7844 AAASZHAAEAAAACXAAJ 4_151_9 7876 AAASZHAAEAAAACXAAK 4_151_10 7900 AAASZHAAEAAAACXAAL 4_151_11 7902 AAASZHAAEAAAACXAAM 4_151_12 7934 AAASZHAAEAAAACXAAN 4_151_13
(二)、索引訪問
索引訪問的成本:一部分時訪問相關的B樹索引的成本,另外一個成本是回表的成本(根據索引中的rowid)
一、索引惟一性掃描(index unique scan):創建是惟一索引,能創建惟一索引的必定要創建惟一索引
二、索引範圍掃描(index range scan):謂詞條件中>、<等
三、索引全掃描(index full scan):掃描目標索引中全部的塊的全部索引行。從最左的葉子節點讀到底,由於葉子是一個雙向鏈表
四、索引快速全掃描(INDEX FAST FULL SCAN)
索引全掃描相似,讀取全部葉子塊的索引行
與全索引掃描不一樣點
五、索引跳躍式掃描(INDEX SKIP SCAN)
適用複合B數索引,謂詞中的過濾條件不是以索引前導列。
只是對前導列作distinct:如create index ind_1 ON emp(job,empno)
Select * from emp where empno=7499
若是job有兩個CLERK,SALESMAN
等同的語句
Select * from emp where job='CLERK' AND empno=7499 UNION ALL Select * from emp where job='SALESMAN' AND empno=7499
oracle中的索引跳躍式掃描僅僅適用那些目標索引前導列的distinct值數量較少、後續非前導列的可選擇性又很是好的情形,由於索引跳躍式掃描的執行效率必定會隨着目標索引前導列的distinct值數量的遞增而遞減
4、錶鏈接
(一)、錶鏈接順序
無論目標SQL中有多少個表作錶鏈接,ORACLE在實際執行都是先作兩兩作錶鏈接,在依次執行這樣的兩兩錶鏈接過程,直到目標SQL中全部表都已經鏈接完畢。
錶鏈接很重要的是驅動表(outer table)和被驅動表(inner table)。
(二)、錶鏈接方法
一、若是驅動表所對應的驅動結果集的記錄數較少,同時在被驅動表的鏈接列上又存在惟一性索引(或者在被驅動表的鏈接列上存在選擇性很好的非惟一性索引),那麼此時使用嵌套循環鏈接的執行效率很是高。
二、大表也能夠做爲驅動表,關鍵看大表的謂詞條件是否能夠把驅動表的結果集的數據量降低下來
一、哈希鏈接不必定會排序,或者說大多數狀況下都不須要排序
二、哈希鏈接的驅動表所對應的鏈接列的可選擇性應儘量好,由於這個可選擇性會影響對應hash bucket中的記錄數,而hash bucket中的記錄數又會直接影響從該hash bucket中查詢匹配記錄的記錄。若是一個hash bucket裏所包含的記錄數過多,則可能或嚴重下降所對應哈希鏈接的執行效率,此時典型的表現就是該哈希鏈接執行了不少時間都沒有結束,數據庫所在數據庫服務器上的CPU佔用率很高,但目標SQL所消耗的邏輯讀卻很低,由於此時大部分時間都耗費在了遍歷上述Hash Bucket裏的全部記錄上,而遍歷Hash Bucket裏的記錄這個動做發生在PGA的工做區裏,因此不耗費邏輯讀。
三、哈希鏈接只適用於CBO,它也只能用於等值鏈接條件(即便是哈希反鏈接,Oracle實際上也是講其轉換成了等價的等值鏈接)。
四、哈希鏈接很適合小表和大表之間作鏈接且鏈接結果集的記錄數較多的情形,特別是在小表的鏈接列的可選擇性很是好的狀況下,這時候哈希鏈接的執行時間就能夠近似看做和全表掃描那個大表所耗費的時間至關。
五、當兩個表作哈希鏈接時,若是在施加目標SQL中指定的謂詞條件(若是有的話)後獲得的數據量較小的那個結果集所對應的hash table、 可以徹底容納在內存中(PGA的工做區),則此時的哈希鏈接的執行效率會很是高
一、一般狀況下,排序合併鏈接的執行效率會遠不如哈希鏈接,但前者的使用範圍更廣,由於哈希鏈接一般只能用於等值鏈接條件,而排序合併鏈接還能用於其餘鏈接條件(<,<=,>,>=)
二、一般狀況下,排序合併鏈接並不適合OLTP類型的系統,器本質緣由是由於對於OLTP類型的系統而言,排序很昂貴的操做,固然,若是能避免排序操做,那麼即便是OLTP類型的系統,也仍是可使用排序合併鏈接的。
三、排序合併鏈接並不存在驅動表的概念
一、無任何鏈接條件,在執行計劃中有cartesian,一般來講,有笛卡爾積,sql語句是有問題的
(三)、錶鏈接的類型
一、內鏈接(Inner JOIN)
--使用= select * from emp a , dept b where a.deptno=b.deptno --join select * from emp a join dept b on a.deptno=b.deptno
二、外鏈接(outer join)
左鏈接--使用(+) select * from emp a,dept b where a.deptno=b.deptno(+) --使用left join select * from emp a left outer join dept b on a.deptno=b.deptno 右鏈接 --使用(+) select * from emp a,dept b where a.deptno(+)=b.deptno --使用left join select * from emp a right outer join dept b on a.deptno=b.deptno
外鏈接的驅動表以(+)對面的表,如以上左鏈接,驅動表爲a,右鏈接的驅動表爲b
三、反鏈接(anti join)
鏈接中not in、not exists 、<>
sql A:select * from emp a WHERE A.DEPTNO NOT IN (SELECT DEPTNO FROM dept b where a.deptno=b.deptno) sql B:select * from emp a WHERE NOT EXISTS (SELECT 1 FROM dept b where a.deptno=b.deptno) sql C:select * from emp a WHERE A.DEPTNO <> all (SELECT DEPTNO FROM dept b where a.deptno=b.deptno)
四、半鏈接(semi join)
鏈接中用in,exists,any
select * from emp a WHERE A.DEPTNO IN (SELECT DEPTNO FROM dept b where a.deptno=b.deptno) select * from emp a WHERE EXISTS (SELECT 1 FROM dept b where a.deptno=b.deptno) select * from emp a WHERE A.DEPTNO =any(SELECT DEPTNO FROM dept b where a.deptno=b.deptno)
五、星形鏈接
在OLTP基本不會用到,在OLAP中用到
參考:崔華《基於ORACLE的SQL優化》