CBO基礎概念

CBO基礎概念

CBO:評估 I/O,CPU,網絡(DBLINK)等消耗的資源成本得出html

1、cardinality

cardinality:集合中包含的記錄數。實際CBO評估目標SQL執行具體步驟的記錄數,cardinality和成本是相關的,cardinality越大,執行步驟中的成本就越大sql

2、Selectivity

Selectivity :謂詞的過濾條件返回的結果的行數佔未加謂詞過濾條件的行數數據庫

公式:=clip_image001[4]服務器

範圍0-1,值越小,說明 選擇性越好 返回的cardinality 越小;值越大,選擇性越差,返回的cardinality 越大。網絡

未加任何謂詞條件結果集: original cardinality,增長謂詞條件爲:computed cardinality。oracle

computed cardinality=original cardinality*selectivityoop

在列上沒有NULL或者直方圖的狀況下,selectivity取值優化

SELECTIVITY=clip_image002ui

NUM_DISTINCT :表示爲列中不一樣值的個數code

3、transitivity(可傳遞性)

CBO會對現有的sql語句作等價轉換,謂詞條件、字段鏈接


優化器基礎概念

1、優化類型:RBO和CBO

(一)、RBO

RBO基於規則的優化器access paths優先級:

  • RBO Path 1: Single Row by Rowid
  • RBO Path 2: Single Row by Cluster Join
  • RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key
  • RBO Path 4: Single Row by Unique or Primary Key
  • RBO Path 5: Clustered Join
  • RBO Path 6: Hash Cluster Key
  • RBO Path 7: Indexed Cluster Key
  • RBO Path 8: Composite Index
  • RBO Path 9: Single-Column Indexes
  • RBO Path 10: Bounded Range Search on Indexed Columns
  • RBO Path 11: Unbounded Range Search on Indexed Columns
  • RBO Path 12: Sort Merge Join
  • RBO Path 13: MAX or MIN of Indexed Column
  • RBO Path 14: ORDER BY on Indexed Column
  • RBO Path 15: Full Table Scan

注意在不違反如上優先級的前提下,如有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):掃描目標索引中全部的塊的全部索引行。從最左的葉子節點讀到底,由於葉子是一個雙向鏈表

  • 索引全掃描的執行結果是有有序的,而且是按照該索引的索引鍵值列來排序,這也意味走索引全掃描可以既達到排序的效果,又同時避免了對該索引的索引鍵值列的真正的排序操做。
  • 索引全掃描時有序的就決定了不可以並行執行,索引全掃描時單塊讀
  • oracle中能作索引全掃描的前提條件是目標索引至少有一個索引鍵值列的屬性是NOT NULL

四、索引快速全掃描(INDEX FAST FULL SCAN)

索引全掃描相似,讀取全部葉子塊的索引行

與全索引掃描不一樣點

  • 索引快速全掃描只適用於CBO
  • 索引快速全掃描可使用多塊讀,也能夠並行執行
  • 索引快速全掃描的執行結果不必定是有序的

五、索引跳躍式掃描(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)。

(二)、錶鏈接方法

  • 嵌套循環鏈接(nested loop)

     一、若是驅動表所對應的驅動結果集的記錄數較少,同時在被驅動表的鏈接列上又存在惟一性索引(或者在被驅動表的鏈接列上存在選擇性很好的非惟一性索引),那麼此時使用嵌套循環鏈接的執行效率很是高。

     二、大表也能夠做爲驅動表,關鍵看大表的謂詞條件是否能夠把驅動表的結果集的數據量降低下來

  • 哈希鏈接(hash join)

     一、哈希鏈接不必定會排序,或者說大多數狀況下都不須要排序

     二、哈希鏈接的驅動表所對應的鏈接列的可選擇性應儘量好,由於這個可選擇性會影響對應hash bucket中的記錄數,而hash bucket中的記錄數又會直接影響從該hash bucket中查詢匹配記錄的記錄。若是一個hash bucket裏所包含的記錄數過多,則可能或嚴重下降所對應哈希鏈接的執行效率,此時典型的表現就是該哈希鏈接執行了不少時間都沒有結束,數據庫所在數據庫服務器上的CPU佔用率很高,但目標SQL所消耗的邏輯讀卻很低,由於此時大部分時間都耗費在了遍歷上述Hash Bucket裏的全部記錄上,而遍歷Hash Bucket裏的記錄這個動做發生在PGA的工做區裏,因此不耗費邏輯讀。

     三、哈希鏈接只適用於CBO,它也只能用於等值鏈接條件(即便是哈希反鏈接,Oracle實際上也是講其轉換成了等價的等值鏈接)。

     四、哈希鏈接很適合小表和大表之間作鏈接且鏈接結果集的記錄數較多的情形,特別是在小表的鏈接列的可選擇性很是好的狀況下,這時候哈希鏈接的執行時間就能夠近似看做和全表掃描那個大表所耗費的時間至關。

     五、當兩個表作哈希鏈接時,若是在施加目標SQL中指定的謂詞條件(若是有的話)後獲得的數據量較小的那個結果集所對應的hash table、 可以徹底容納在內存中(PGA的工做區),則此時的哈希鏈接的執行效率會很是高

  • 排序合併鏈接(merge jion)

    一、一般狀況下,排序合併鏈接的執行效率會遠不如哈希鏈接,但前者的使用範圍更廣,由於哈希鏈接一般只能用於等值鏈接條件,而排序合併鏈接還能用於其餘鏈接條件(<,<=,>,>=)

    二、一般狀況下,排序合併鏈接並不適合OLTP類型的系統,器本質緣由是由於對於OLTP類型的系統而言,排序很昂貴的操做,固然,若是能避免排序操做,那麼即便是OLTP類型的系統,也仍是可使用排序合併鏈接的。

    三、排序合併鏈接並不存在驅動表的概念

  • 笛卡爾積鏈接(Cartesian join)

     一、無任何鏈接條件,在執行計劃中有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優化》

相關文章
相關標籤/搜索