ORACLE:什麼是執行計劃

us_yunleiwang發表於2015-01-09
oracle 
1,什麼是執行計劃
所謂執行計劃,顧名思義,就是對一個查詢任務,做出一份怎樣去完成任務的詳細方案。舉個生活中的例子,我從珠海要去英國,我可以選擇先去香港然後轉機,也可以先去北京轉機,或者去廣州也可以。但是到底怎樣去英國划算,也就是我的費用最少,這是一件值得考究的事情。同樣對於查詢而言,我們提交的SQL僅僅是描述出了我們的目的地是英國,但至於怎麼去,通常我們的SQL中是沒有給出提示資訊的,是由資料庫來決定的。
  我們先簡單的看一個執行計劃的對比:
  SQL> set autotrace traceonly
  執行計劃一:
  SQL> select count(*) from t; 
  COUNT(*) 
  ---------- 
  24815 
  Execution Plan 
  0   Select STATEMENT Optimizer=CHOOSE 
  1  0  SORT (AGGREGATE) 
  2  1   TABLE Access (FULL) OF 'T'
  執行計劃二:
  SQL> select count(*) from t; 
  COUNT(*) 
  24815 
  Execution Plan 
  0   Select STATEMENT Optimizer=CHOOSE (Cost=26 Card=1) 
  1  0  SORT (AGGREGATE) 
  2  1   INDEX (FULL SCAN) OF 'T_INDEX' (NON-UNIQUE) (Cost=26 Card=28180)
  這兩個執行計劃中,第一個表示求和是透過進行全表掃描來做的,把整個表中資料讀入記憶體來逐條累加;第二個表示根據表中索引,把
整個索引讀進記憶體來逐條累加,而不用去讀表中的資料。但是這兩種方式到底哪種快呢?通常來說可能二比一快,但也不是絕對的。這是一
個很簡單的例子演示執行計劃的差異。對於複雜的SQL(表連線、巢狀子查詢等),執行計劃可能幾十種甚至上百種,但是到底那種最好呢?
我們事前並不知道,資料庫本身也不知道,但是資料庫會根據一定的規則或者統計資訊(statistics)去選擇一個執行計劃,通常來說選擇的是
比較優的,但也有選擇失誤的時候,這就是這次討論的價值所在。

oracle最佳化器模式
  Oracle最佳化器有兩大類,基於規則的和基於代價的,在SQLPLUS中我們可以檢視init檔案中定義的預設的最佳化器模式。
  SQL> show parameters optimizer_mode 
  NAME                 TYPE  VALUE 
  optimizer_mode           string  CHOOSE 
  SQL>
  這是Oracle8.1.7 企業版,我們可以看出,預設安裝後資料庫最佳化器模式為CHOOSE,我們還可以設定為 RULE、
FIRST_ROWS,ALL_ROWS。可以在init檔案中對整個instance的所有會話設定,也可以單獨對某個會話設定:
  SQL> Alter SESSION SET optimizer_mode = RULE; 
  會話已更改。 
  SQL> Alter SESSION SET optimizer_mode = FIRST_ROWS; 
  會話已更改。 
  SQL> Alter SESSION SET optimizer_mode = ALL_ROWS; 
  會話已更改。
  基於規則的查詢,資料庫根據表和索引等定義資訊,按照一定的規則來產生執行計劃;基於代價的查詢,資料庫根據蒐集的表和索引的
資料的統計資訊(透過analyze 命令或者使用dbms_stats包來蒐集)綜合來決定選取一個資料庫認為最優的執行計劃(實際上不一定最優)。
RULE是基於規則的,CHOOSE表示如果查詢的表存在蒐集的統計資訊則基於代價來執行(在CHOOSE模式下Oracle採用的是 FIRST_ROWS)
,否則基於規則來執行。在基於代價的兩種方式中,FIRST_ROWS指執行計劃採用最少資源儘快的返回部分結果給客戶端,對於排序分頁
頁顯示這種查詢尤其適用,ALL_ROWS指以總體消耗資源最少的方式返回結果給客戶端。
  基於規則的模式下,資料庫的執行計劃通常比較穩定。但在基於代價的模式下,我們才有更大的機會選擇最優的執行計劃。也由於
oracle的很多查詢方面的特性必須在基於代價的模式下才能體現出來,所以我們通常不選擇RULE(並且Oracle宣稱從 oracle 10i版本資料庫
開始將不再支援 RULE)。既然是基於代價的模式,也就是說執行計劃的選擇是根據表、索引等定義和資料的統計資訊來決定的,這個統計
資訊是根據 analyze 命令或者dbms_stats包來定期蒐集的。首先存在著一種可能,就是由於蒐集資訊是一個很消耗資源和時間的動作,尤
其當表資料量很大的時候,因為蒐集資訊是對整個表資料進行重新的完全統計,所以這是我們必須慎重考慮的問題。我們只能在伺服器空
閒的時候定期的進行資訊蒐集。這說明我們在一段時期內,統計資訊可能和資料庫本身的資料並不吻合;另外就是Oracle的統計資料本身也
存在著不精確部分(詳細參考Oracle DOCUMENT),更重要的一個問題就是及時統計資料相對已經比較準確,但是Oracle的最佳化器的選擇也
並不是始終是最優的方案。這也倚賴於Oracle對不同執行計劃的代價的計算規則(我們通常是無法知道具體的計算規則的)。這好比我們決定
從香港還是從北京去英國,車票、機票等實際價格到底是怎麼核算出來的我們並不知道,或者說我們現在瞭解的價格資訊,在我們乘車前
往的時候,真實價格跟我們的預算已經發生了變化。所有的因素,都將影響我們的整個開銷。
  執行計劃穩定效能帶給我們什麼
  Oracle存在著執行計劃選擇失誤的可能。這也是我們經常遇見的一些現象,比如總有人說我的程式在測試資料庫中跑的很好,但在產
品資料庫上就是跑的很差,甚至後者硬體條件比前者還好,這到底是為什麼?硬體資源、統計資訊、引數設定都可能對執行計劃產生影響。
由於因素太多,我們總是對未來懷著一種莫名的恐懼,我的產品資料庫上線後到底跑的好不好?於是Oracle提供了一種穩定執行計劃的能力
,也就是把在測試環境中的執行良好的執行計劃所產生的OUTLINES移植到產品資料庫,使得執行計劃不會隨著其他因素的變化而變化。
  那麼OUTLINES是什麼呢?先要介紹一個內容,Oracle提供了在SQL中使用HINTS來引導最佳化器產生我們想要的執行計劃的能力。這在
多表連線、複雜查詢中特別有效。HINTS的型別很多,可以設定最佳化器目標(RULE、CHOOSE、FIRST_ROWS、ALL_ROWS),可以指定表
連線的順序,可以指定使用哪個表的哪個索引等等,可以對SQL進行很多精細的控制。透過這種方式產生我們想要的執行計劃的這些
HINTS,Oracle可以儲存這些HINTS,我們稱之為OUTLINES。透過STORE OUTLINES可以使得我們擁有以後產生相同執行計劃的能力,也
就是使我們擁有了穩定執行計劃的能力。
  這裡想給出一個附加的說明就是,實際上,我們透過工具改寫SQL,比如使用SQL EXPERT改寫後的SQL,這些不僅僅是加了HINTS
而且文字都已經發生了變化的SQL,也可以儲存OUTLINES,並可被應用到應用中。但這不是一定生效,我們必須測試檢查是否生效。但由
於就算給了錯誤的OUTLINES,資料庫在執行的時候,也只是忽略過去重新生成執行計劃而不會返回錯誤,所以我們才敢放心的這麼使用。
當然在Oracle文件中並沒有指明可以這樣做,文件中只是說明,如果存在OUTLINES的同時又在SQL中加了HINTS,則會使用OUTLINES而
忽略HINTS。這個功能在LECCO將釋出的產品中會使用這一功能,這樣可以將SQL EXPERT的改寫SQL的能力和穩定執行計劃的能力結合起
來,那麼我們就對不能更改原始碼的應用具有了相當強大的SQL最佳化能力。
  也許我們會有疑問,假如穩定了執行計劃,那還蒐集統計資訊幹嗎?這是因為幾個原因造成的,首先,現在的執行計劃對於未來發生了
變化的資料未必就是合適的,存在著當前的執行計劃不滿足未來資料的變化後的效率,而新的統計資訊的情況下所產生的執行計劃也並不
是全部都合理的。那這個時候,我們可以採用新蒐集的統計資訊,但是卻對新統計資訊下不良的執行計劃採用Oracle提供的執行計劃穩定
性這個能力固定執行計劃,這樣結合起來我們可以建立滿意的高效的資料庫執行環境。
  我們還需要關注的一個東西,Oracle提供的dbms_stats包除了具有蒐集統計資訊的能力,還具有把資料庫中統計資訊(statistics)
export/import的能力,還具有隻蒐集統計資訊而使得統計資訊不應用於資料庫的能力(把統計資訊蒐集到一個特定的表中而不是立即生效)
,在這個基礎上我們就可以把統計資訊export出來再import到一個測試環境中,再執行我們的應用,在測試環境中我們觀察最新的統計信
息會導致哪些執行計劃發生變化(DB EXPERT的Plan Version Tracer是模擬不同環境並自動檢查不同環境中執行計劃變化的工具),是變好了
還是變差了。我們可以把變差的這一部分在測試環境中使用hints或者利用工具(SQL EXPERT是在重寫SQL這一領域目前最強有力的工具)產
生良好的執行計劃的SQL,利用這些SQL可以產生OUTLINES,然後在產品資料庫應用最新的統計資訊的同時移植進這些OUTLINES。
  最後說一下我們不得不使用執行計劃穩定效能力的場合。我們假定Oracle的最佳化器的選擇都是準確的,但是最佳化器選擇的基礎就是我
們的SQL,這些SQL才從根本上決定了執行效率,這是更重要的一個最佳化的環節。SQL是基礎(當然資料庫的設計是基礎的基礎),一個SQL寫
的好不好,就相當於我們同樣是要想去英國,但是我的起點在珠海,你的起點卻在西藏的最邊緣偏僻的一個地方,那不管你做怎樣的最優
路線選擇,你都不如我在珠海去英國所花費的代價小。
2,怎麼生成的
1.Explain plan
explain plan for 
select * from aa;
檢視結果:
select * from table(dbms_xplan.display()); 
2.Autotrace 
Set timing on --記錄所用時間
Set autottrace on/traceonly--自動記錄執行計劃
3.SQL_TRACE
orACLE SQL_TRACE
“SQL TRACE”是Oracle提供的用於進行SQL跟蹤的手段,是強有力的輔助診斷工具。在日常的資料庫問題診斷和解決中,“SQL TRACE”是
非常常用的方法。
一般,一次跟蹤可以分為以下幾步:
    1、界定需要跟蹤的目標範圍,並使用適當的命令啟用所需跟蹤。
    2、經過一段時間後,停止跟蹤。此時應該產生了一個跟蹤結果檔案。
    3、找到跟蹤檔案,並對其進行格式化,然後閱讀或分析。
本文就“SQL TRACE”的這些使用作簡單探討,並透過具體案例對SQL_TRACE的使用進行說明。
3,怎麼檢視執行計劃
從Oracle10g開始,可以透過EXPLAIN PLAN FOR檢視DDL語句的執行計劃了。


在9i及以前版本,Oracle只能看到DML的執行計劃,不過從10g開始,透過EXPLAIN PLAN FOR的方式,已經可以看到DDL語句的執行計劃
了。
這對於研究Create TABLE AS Select、Create MATERIALIZED VIEW AS Select以及Create INDEX,Alter INDEX REBUILD等語
句有很大的幫助。
舉個簡單的例子,Oracle的文件上對於索引的建立有如下描述:
The optimizer can use an existing index to build another index. This results in a much faster index build.
如果看不到DDL的執行計劃,只能根據執行時間的長短去猜測Oracle的具體執行計劃,但是這種方法沒有足夠的說服力。但是透過DDL的執
行計劃,就使得結果一目瞭然了。
SQL> Create TABLE T AS Select * FROM DBA_OBJECTS;
表已建立。
SQL> EXPLAIN PLAN FOR
2 Create INDEX IND_T_NAME ON T(OBJECT_NAME);
已解釋。
SQL> Select * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
Plan hash value: 3035241083
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | Create INDEX STATEMENT | | 57915 | 3732K| 75 (2)| 00:00:01 |
| 1 | INDEX BUILD NON UNIQUE| IND_T_NAME | | | | |
| 2 | SORT Create INDEX | | 57915 | 3732K| | |
| 3 | TABLE ACCESS FULL | T | 57915 | 3732K| 41 (3)| 00:00:01 |
-------------------------------------------------------------------------------------
Note
-----
- estimated index size: 5242K bytes
已選擇14行。
SQL> Create INDEX IND_T_OWNER_NAME ON T(OWNER, OBJECT_NAME);
索引已建立。
SQL> EXPLAIN PLAN FOR
2 Create INDEX IND_T_NAME ON T(OBJECT_NAME);
已解釋。
SQL> Select * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 517242163
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | Create INDEX STATEMENT | | 57915 | 3732K| 75 (2)| 00:00:01 |
| 1 | INDEX BUILD NON UNIQUE| IND_T_NAME | | | | |
| 2 | SORT Create INDEX | | 57915 | 3732K| | |
| 3 | INDEX FAST FULL SCAN| IND_T_OWNER_NAME | | | | |
-------------------------------------------------------------------------------------------
Note
-----
- estimated index size: 5242K bytes
已選擇14行。
SQL> SET AUTOT ON
SQL> Create INDEX IND_T_NAME ON T(OBJECT_NAME);
索引已建立。
注意,檢視DDL的執行計劃需要使用EXPLAIN PLAN FOR,AUTOTRACE對於DDL是無效的。
4,如何讀懂執行計劃:
Execution Plan
----------------------------------------------------------
0 Select STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'USER_INFO'
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'USER_NUM_TABLE'
5 3 INDEX (RANGE SCAN) OF 'PK_USER_INFO' (UNIQUE)
請問以上執行計劃語句是如何看的?語句的執行順序是什麼? 
讓我們來解釋一下怎麼看吧,左邊的兩列數字,第一列表示這條計劃的編號,第二列是這條計劃的父計劃的編號;如果一條計劃有子計劃,
那麼先要執行其子計劃;在這個例子中:從第一條編號為0的(Select STATEMENT ptimizer=CHOOSE)開始,他有個子計劃1(SORT
(AGGREGATE)),然後1有個子計劃2,2有子計劃3, 3 有子計劃4和5,4是3的第一個子計劃,所以先執行4(TABLE ACCESS (FULL)
OF 'USER_NUM_TABLE'),再執行5(INDEX (RANGE SCAN) OF 'PK_USER_INFO' (UNIQUE)),4和5執行完返回到其父計劃3(NESTED
LOOPS),3把4和5取到的rows進行nested loops,結果再返回到2,再到1排序,再到0select.
舉例:
SQL> conn scott/tiger
已連線。
SQL> set autotrace traceonly;
SQL> Select count(1) FROM dim_hy;

Execution Plan
----------------------------------------------------------
   0      Select STATEMENT Optimizer=CHOOSE (Cost=6 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     TABLE ACCESS (FULL) OF 'DIM_HY' (Cost=6 Card=1801)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         45  consistent gets
          0  physical reads
          0  redo size
        377  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
SQL> desc dim_hy
名稱                                      是否為空? 型別
----------------------------------------- -------- ----------------------------
HY_ID                                     NOT NULL NUMBER(10)
HY_DM                                     NOT NULL VARCHAR2(6)
HY_MC                                     NOT NULL VARCHAR2(40)
HY_MXID                                            NUMBER(10)
HY_MXDM                                            VARCHAR2(6)
HY_MXMC                                            VARCHAR2(40)
HY_ZLID                                            NUMBER(10)
HY_ZLDM                                            VARCHAR2(6)
HY_ZLMC                                            VARCHAR2(40)
HY_DLID                                            NUMBER(10)
HY_DLDM                                            VARCHAR2(6)
HY_DLMC                                            VARCHAR2(40)
HY_MLID                                            NUMBER(10)
HY_MLDM                                            VARCHAR2(6)
HY_MLMC                                            VARCHAR2(30)
HY_CCLX                                   NOT NULL VARCHAR2(10)
HY_CCMC                                   NOT NULL VARCHAR2(10)
CY_ID                                              NUMBER(6)
CY_LXDM                                            CHAR(1)
CY_LXMS                                            VARCHAR2(20)
HY_SJ_ID                                           NUMBER(10)
YXBZ                                      NOT NULL CHAR(1)
YXQQ                                      NOT NULL DATE
YXQZ                                      NOT NULL DATE

SQL> Create INDEX idx_dim_hy ON dim_hy(hy_id);
索引已建立。
SQL> Select count(1) FROM dim_hy;

Execution Plan
----------------------------------------------------------
   0      Select STATEMENT Optimizer=CHOOSE (Cost=4 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     INDEX (FAST FULL SCAN) OF 'IDX_DIM_HY' (NON-UNIQUE) (Cos
          t=4 Card=1801)


Statistics
----------------------------------------------------------
         14  recursive calls
          0  db block gets
         10  consistent gets
          4  physical reads
          0  redo size
        377  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed



================================================================================================

SQL> conn sys/sys as sysdba
已連線。
SQL> show parameter optimizer_mode;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_mode                       string      CHOOSE
SQL> Alter SESSION SET optimizer_mode = RULE;
會話已更改。
SQL> Alter SESSION SET optimizer_mode = TEST ;
ERROR:
orA-00096: 值 TEST 對引數 optimizer_mode 無效,它必須來自 first_rows_1000,
first_rows_100, first_rows_10, first_rows_1, first_rows, all_rows, choose, rule
之間

SQL> Alter SESSION SET optimizer_mode = CHOOSE;
會話已更改。

==================================================================================================
SQL> EXPLAIN PLAN FOR Select count(*) FROM dim_hy;
已解釋。
SQL> Select * FROM TABLE(dbms_xplan.display()) ;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------------------------
| Id  | Operation             |  Name       | Rows  | Bytes | Cost  |
---------------------------------------------------------------------
|   0 | Select STATEMENT      |             |     1 |       |     4 |
|   1 |  SORT AGGREGATE       |             |     1 |       |       |
|   2 |   INDEX FAST FULL SCAN| IDX_DIM_HY  |  1801 |       |     4 |
---------------------------------------------------------------------
Note: cpu costing is off
已選擇10行。

SQL> SET TIMING ON;
SQL> EXPLAIN PLAN FOR Select count(1) FROM dim_hy;
已解釋。
已用時間:  00: 00: 00.00
SQL> Select * FROM TABLE(dbms_xplan.display()) ;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------------------------
| Id  | Operation             |  Name       | Rows  | Bytes | Cost  |
---------------------------------------------------------------------
|   0 | Select STATEMENT      |             |     1 |       |     4 |
|   1 |  SORT AGGREGATE       |             |     1 |       |       |
|   2 |   INDEX FAST FULL SCAN| IDX_DIM_HY  |  1801 |       |     4 |
---------------------------------------------------------------------
Note: cpu costing is off
已選擇10行。
已用時間:  00: 00: 00.00

======================================================================================

SQL> Create TABLE hy AS Select *  FROM dim_hy;
表已建立。
已用時間:  00: 00: 00.04
SQL> EXPLAIN PLAN FOR Create INDEX idx_hy_id ON hy(hy_id);
已解釋。
已用時間:  00: 00: 00.00
SQL> Select * FROM TABLE(dbms_xplan.display()) ;
已選擇11行。
已用時間:  00: 00: 00.00
Execution Plan
----------------------------------------------------------
   0      Select STATEMENT Optimizer=CHOOSE
   1    0   COLLECTION ITERATOR (PICKLER FETCH) OF 'DISPLAY'


Statistics
----------------------------------------------------------
         13  recursive calls
          0  db block gets
         22  consistent gets
          0  physical reads
          0  redo size
       1061  bytes sent via SQL*Net to client
        503  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          9  sorts (memory)
          0  sorts (disk)
         11  rows processed
SQL> Select * FROM hy;
已選擇1801行。
已用時間:  00: 00: 00.01
Execution Plan
----------------------------------------------------------
   0      Select STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (FULL) OF 'HY'


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        162  consistent gets
         42  physical reads
          0  redo size
     139471  bytes sent via SQL*Net to client
       1823  bytes received via SQL*Net from client
        122  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       1801  rows processed
SQL> Select * FROM TABLE(dbms_xplan.display()) ;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
----------------------------------------------------------------------
| Id  | Operation              |  Name       | Rows  | Bytes | Cost  |
----------------------------------------------------------------------
|   0 | Create INDEX STATEMENT |             |       |       |       |
|   1 |  INDEX BUILD NON UNIQUE| IDX_HY_ID   |       |       |       |
|   2 |   SORT Create INDEX    |             |       |       |       |
|   3 |    TABLE ACCESS FULL   | HY          |       |       |       |
----------------------------------------------------------------------
Note: rule based optimization
已選擇11行。
===========================================================================================
SQL> SET AUTOTRACE TRACEONLY;
SQL> Select m.hy_id, n.hy_mc FROM hy m, dim_hy n Where m.hy_id = n.hy_id ;
已選擇1801行。
已用時間:  00: 00: 00.01
Execution Plan
----------------------------------------------------------
   0      Select STATEMENT Optimizer=CHOOSE (Cost=13 Card=1801 Bytes=5
          5831)
   1    0   HASH JOIN (Cost=13 Card=1801 Bytes=55831)
   2    1     TABLE ACCESS (FULL) OF 'HY' (Cost=6 Card=1801 Bytes=2341
          3)
   3    1     TABLE ACCESS (FULL) OF 'DIM_HY' (Cost=6 Card=1801 Bytes=
          32418)


Statistics
----------------------------------------------------------
         31  recursive calls
          0  db block gets
        258  consistent gets
          0  physical reads
          0  redo size
      52655  bytes sent via SQL*Net to client
       1823  bytes received via SQL*Net from client
        122  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       1801  rows processed


==============================================================================================================================================================================

本文全面詳細介紹oracle執行計劃的相關的概念,訪問資料的存取方法,表之間的連線等內容。
    並有總結和概述,便於理解與記憶!
+++
目錄
---
    一.相關的概念
    Rowid的概念
    Recursive Sql概念
    Predicate(謂詞)
    DRiving Table(驅動表)
    Probed Table(被探查表)
    組合索引(concatenated index)
    可選擇性(selectivity)
    二.oracle訪問資料的存取方法
    1) 全表掃描(Full Table Scans, FTS)
    2) 透過ROWID的表存取(Table Access by ROWID或rowid lookup)
    3)索引掃描(Index Scan或index lookup)有4種型別的索引掃描:
     (1) 索引唯一掃描(index unique scan)
     (2) 索引範圍掃描(index range scan)
           在非唯一索引上都使用索引範圍掃描。使用index rang scan的3種情況:
        (a) 在唯一索引列上使用了range運算子(> < <> >= <= between)
        (b) 在組合索引上,只使用部分列進行查詢,導致查詢出多行
        (c) 對非唯一索引列上進行的任何查詢。  
     (3) 索引全掃描(index full scan)
     (4) 索引快速掃描(index fast full scan)
    三、表之間的連線
    1,排序 - - 合併連線(Sort Merge Join, SMJ)
    2,巢狀迴圈(Nested Loops, NL)
    3,雜湊連線(Hash Join, HJ)
    另外,笛卡兒乘積(Cartesian Product)
    總結Oracle連線方法
    
    oracle執行計劃總結概述
+++
  一.相關的概念
  Rowid的概念:rowid是一個偽列,既然是偽列,那麼這個列就不是使用者定義,而是系統自己給加上的。 對每個表都有一個rowid的偽列,但是表中並不物理儲存ROWID列的值。不過你可以像使用其它列那樣使用它,但是不能刪除改列,也不能對該列的值進行 修改、插入。一旦一行資料插入資料庫,則rowid在該行的生命週期內是唯一的,即即使該行產生行遷移,行的rowid也不會改變。
  Recursive SQL概念:有時為了執行使用者發出的一個sql語句,Oracle必須執行一些額外的語句,我們將這些額外的語句稱之為''recursive calls''或''recursive SQL statements''.如當一個DDL語句發出後,ORACLE總是隱含的發出一些recursive SQL語句,來修改資料字典資訊,以便使用者可以成功的執行該DDL語句。當需要的資料字典資訊沒有在共享記憶體中時,經常會發生Recursive calls,這些Recursive calls會將資料字典資訊從硬碟讀入記憶體中。使用者不比關心這些recursive SQL語句的執行情況,在需要的時候,ORACLE會自動的在內部執行這些語句。當然DML語句與Select都可能引起recursive SQL.簡單的說,我們可以將觸發器視為recursive SQL.
  Row Source(行源):用在查詢中,由上一操作返回的符合條件的行的集合,即可以是表的全部行資料的集合;也可以是表的部分行資料的集合;也可以為對上2個row source進行連線操作(如join連線)後得到的行資料集合。
  Predicate(謂詞):一個查詢中的Where限制條件
  Driving Table(驅動表):該表又稱為外層表(OUTER TABLE)。這個概念用於巢狀與HASH連線中。如果該row source返回較多的行資料,則對所有的後續操作有負面影響。注意此處雖然翻譯為驅動表,但實際上翻譯為驅動行源(driving row source)更為確切。一般說來,是應用查詢的限制條件後,返回較少行源的表作為驅動表,所以如果一個大表在Where條件有有限制條件(如等值限 制),則該大表作為驅動表也是合適的,所以並不是只有較小的表可以作為驅動表,正確說法應該為應用查詢的限制條件後,返回較少行源的表作為驅動表。在執行 計劃中,應該為靠上的那個row source,後面會給出具體說明。在我們後面的描述中,一般將該表稱為連線操作的row source 1.
  Probed Table(被探查表):該表又稱為內層表(INNER TABLE)。在我們從驅動表中得到具體一行的資料後,在該表中尋找符合連線條件的行。所以該表應當為大表(實際上應該為返回較大row source的表)且相應的列上應該有索引。在我們後面的描述中,一般將該表稱為連線操作的row source 2.
  組合索引(concatenated index):由多個列構成的索引,如create index idx_emp on emp(col1, col2, col3, ……),則我們稱idx_emp索引為組合索引。在組合索引中有一個重要的概念:引導列(leading column),在上面的例子中,col1列為引導列。當我們進行查詢時可以使用“where col1 = ? ”,也可以使用“where col1 = ? and col2 = ?”,這樣的限制條件都會使用索引,但是“where col2 = ? ”查詢就不會使用該索引。所以限制條件中包含先導列時,該限制條件才會使用該組合索引。
  可選擇性(selectivity):比較一下列中唯一鍵的數量和表中的行數,就可以判斷該列的可選擇性。 如果該列的“唯一鍵的數量/表中的行數”的比值越接近1,則該列的可選擇性越高,該列就越適合建立索引,同樣索引的可選擇性也越高。在可選擇性高的列上進 行查詢時,返回的資料就較少,比較適合使用索引查詢。
  二.oracle訪問資料的存取方法
  1) 全表掃描(Full Table Scans, FTS)
  為實現全表掃描,Oracle讀取表中所有的行,並檢查每一行是否滿足語句的Where限制條件一個多塊讀操作可以使一次I/O能讀取多塊資料塊(db_block_multiblock_read_count引數設定),而不是隻讀取一個資料塊,這極大的減 少了I/O總次數,提高了系統的吞吐量,所以利用多塊讀的方法可以十分高效地實現全表掃描,而且只有在全表掃描的情況下才能使用多塊讀操作。在這種訪問模 式下,每個資料塊只被讀一次。
  使用FTS的前提條件:在較大的表上不建議使用全表掃描,除非取出資料的比較多,超過總量的5% —— 10%,或你想使用並行查詢功能時。
  使用全表掃描的例子: 
  SQL> explain plan for select * from dual;
  Query Plan
  -----------------------------------------
  Select STATEMENT[CHOOSE] Cost=
  TABLE ACCESS FULL DUAL
  2) 透過ROWID的表存取(Table Access by ROWID或rowid lookup)
  行的ROWID指出了該行所在的資料檔案、資料塊以及行在該塊中的位置,所以透過ROWID來存取資料可以快速定位到目標資料上,是Oracle存取單行資料的最快方法。
  這種存取方法不會用到多塊讀操作,一次I/O只能讀取一個資料塊。我們會經常在執行計劃中看到該存取方法,如透過索引查詢資料。
  使用ROWID存取的方法: 
  SQL> explain plan for select * from dept where rowid = ''AAAAyGAADAAAAATAAF'';

  Query Plan
  ------------------------------------
  Select STATEMENT [CHOOSE] Cost=1
  TABLE ACCESS BY ROWID DEPT [ANALYZED]
  3)索引掃描(Index Scan或index lookup)
  我們先透過index查詢到資料對應的rowid值(對於非唯一索引可能返回多個rowid值),然後根據rowid直接從表中得到具體的資料,這 種查詢方式稱為索引掃描或索引查詢(index lookup)。一個rowid唯一的表示一行資料,該行對應的資料塊是透過一次i/o得到的,在此情況下該次i/o只會讀取一個資料庫塊。
  在索引中,除了儲存每個索引的值外,索引還儲存具有此值的行對應的ROWID值。
  索引掃描可以由2步組成:
  (1) 掃描索引得到對應的rowid值。
  (2) 透過找到的rowid從表中讀出具體的資料。
  每步都是單獨的一次I/O,但是對於索引,由於經常使用,絕大多數都已經CACHE到記憶體中,所以第1步的 I/O經常是邏輯I/O,即資料可以從記憶體中得到。但是對於第2步來說,如果表比較大,則其資料不可能全在記憶體中,所以其I/O很有可能是物理I/O,這 是一個機械操作,相對邏輯I/O來說,是極其費時間的。所以如果多大表進行索引掃描,取出的資料如果大於總量的5% —— 10%,使用索引掃描會效率下降很多。如下列所示:
  SQL> explain plan for select empno, ename from emp where empno=10;
  Query Plan
  ------------------------------------
  Select STATEMENT [CHOOSE] Cost=1
  TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX UNIQUE SCAN EMP_I1
  但是如果查詢的資料能全在索引中找到,就可以避免進行第2步操作,避免了不必要的I/O,此時即使透過索引掃描取出的資料比較多,效率還是很高的
  SQL> explain plan for select empno from emp where empno=10;-- 只查詢empno列值
  Query Plan
  ------------------------------------
  Select STATEMENT [CHOOSE] Cost=1
  INDEX UNIQUE SCAN EMP_I1
  進一步講,如果sql語句中對索引列進行排序,因為索引已經預先排序好了,所以在執行計劃中不需要再對索引列進行排序
  SQL> explain plan for select empno, ename from emp
  where empno > 7876 order by empno;
  Query Plan
  --------------------------------------------------------------------------------
  Select STATEMENT[CHOOSE] Cost=1
  TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]
  從這個例子中可以看到:因為索引是已經排序了的,所以將按照索引的順序查詢出符合條件的行,因此避免了進一步排序操作。
  根據索引的型別與where限制條件的不同,有4種型別的索引掃描:
  索引唯一掃描(index unique scan)
  索引範圍掃描(index range scan)
  索引全掃描(index full scan)
  索引快速掃描(index fast full scan)
  (1) 索引唯一掃描(index unique scan)
  透過唯一索引查詢一個數值經常返回單個ROWID.如果存在UNIQUE 或PRIMARY KEY 約束(它保證了語句只存取單行)的話,Oracle經常實現唯一性掃描。
  使用唯一性約束的例子:
  SQL> explain plan for
  select empno,ename from emp where empno=10;
  Query Plan
  ------------------------------------
  Select STATEMENT [CHOOSE] Cost=1
  TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX UNIQUE SCAN EMP_I1
  (2) 索引範圍掃描(index range scan)
  使用一個索引存取多行資料,在唯一索引上使用索引範圍掃描的典型情況下是在謂詞(where限制條件)中使用了範圍運算子(如>、、>=、<=、between)
  使用索引範圍掃描的例子:
  SQL> explain plan for select empno,ename from emp
  where empno > 7876 order by empno;
  Query Plan
  --------------------------------------------------------------------------------
  Select STATEMENT[CHOOSE] Cost=1
  TABLE ACCESS BY ROWID EMP [ANALYZED]
  INDEX RANGE SCAN EMP_I1 [ANALYZED]
  在非唯一索引上,謂詞col = 5可能返回多行資料,所以在非唯一索引上都使用索引範圍掃描。
  使用index rang scan的3種情況:
  (a) 在唯一索引列上使用了range運算子(> < <> >= <= between)
  (b) 在組合索引上,只使用部分列進行查詢,導致查詢出多行
  (c) 對非唯一索引列上進行的任何查詢。
  (3) 索引全掃描(index full scan)
  與全表掃描對應,也有相應的全索引掃描。而且此時查詢出的資料都必須從索引中可以直接得到。
  全索引掃描的例子:
  An Index full scan will not perform. single block i/o''s and so it may prove to be inefficient.
  e.g.
  Index BE_IX is a concatenated index on big_emp (empno, ename)
  SQL> explain plan for select empno, ename from big_emp order by empno,ename;
  Query Plan
  --------------------------------------------------------------------------------
  Select STATEMENT[CHOOSE] Cost=26
  INDEX FULL SCAN BE_IX [ANALYZED]
  (4) 索引快速掃描(index fast full scan)
  掃描索引中的所有的資料塊,與 index full scan很類似,但是一個顯著的區別就是它不對查詢出的資料進行排序,即資料不是以排序順序被返回。在這種存取方法中,可以使用多塊讀功能,也可以使用並行讀入,以便獲得最大吞吐量與縮短執行時間。
  索引快速掃描的例子:
  BE_IX索引是一個多列索引: big_emp (empno,ename)
  SQL> explain plan for select empno,ename from big_emp;
  Query Plan
  ------------------------------------------
  Select STATEMENT[CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]
  只選擇多列索引的第2列:
  SQL> explain plan for select ename from big_emp;
  Query Plan
  ------------------------------------------
  Select STATEMENT[CHOOSE] Cost=1
  INDEX FAST FULL SCAN BE_IX [ANALYZED]
  三、表之間的連線
  Join是一種試圖將兩個表結合在一起的謂詞,一次只能連線2個表,表連線也可以被稱為表關聯。在後面的敘 述中,我們將會使用“row source”來代替“表”,因為使用row source更嚴謹一些,並且將參與連線的2個row source分別稱為row source1和row source 2.Join過程的各個步驟經常是序列操作,即使相關的row source可以被並行訪問,即可以並行的讀取做join連線的兩個row source的資料,但是在將表中符合限制條件的資料讀入到記憶體形成row source後,join的其它步驟一般是序列的。有多種方法可以將2個表連線起來,當然每種方法都有自己的優缺點,每種連線型別只有在特定的條件下才會 發揮出其最大優勢。
  row source(表)之間的連線順序對於查詢的效率有非常大的影響。透過首先存取特定的表,即將該表作為驅動表,這樣可以先應用某些限制條件,從而得到一個 較小的row source,使連線的效率較高,這也就是我們常說的要先執行限制條件的原因。一般是在將表讀入記憶體時,應用where子句中對該表的限制條件。
  根據2個row source的連線條件的中運算子的不同,可以將連線分為等值連線(如Where A.COL3 = B.COL4)、非等值連線(Where A.COL3 > B.COL4)、外連線(Where A.COL3 = B.COL4(+))。上面的各個連線的連線原理都基本一樣,所以為了簡單期間,下面以等值連線為例進行介紹。
  在後面的介紹中,都以以下Sql為例進行說明:
  Select A.COL1, B.COL2
  FROM A, B
  Where A.COL3 = B.COL4;
  假設A表為Row Soruce1,則其對應的連線操作關聯列為COL 3;
  B表為Row Soruce2,則其對應的連線操作關聯列為COL 4;
  連線型別:
  目前為止,無論連線運算子如何,典型的連線型別共有3種:
  排序 - - 合併連線(Sort Merge Join (SMJ) )
  巢狀迴圈(Nested Loops (NL) )
  雜湊連線(Hash Join)
  另外,還有一種Cartesian product(笛卡爾積),一般情況下,儘量避免使用。
  1,排序 - - 合併連線(Sort Merge Join, SMJ)
  內部連線過程:
  1) 首先生成row source1需要的資料,然後對這些資料按照連線操作關聯列(如A.col3)進行排序。
  2) 隨後生成row source2需要的資料,然後對這些資料按照與sort source1對應的連線操作關聯列(如B.col4)進行排序。
  3) 最後兩邊已排序的行被放在一起執行合併操作,即將2個row source按照連線條件連線起來
  下面是連線步驟的圖形表示:
  MERGE
  /\
  SORTSORT
  ||
  Row Source 1Row Source 2
  如果row source已經在連線關聯列上被排序,則該連線操作就不需要再進行sort操作,這樣可以大大提高這種連線操作的連線速度,因為排序是個極其費資源的操 作,特別是對於較大的表。預先排序的row source包括已經被索引的列(如a.col3或b.col4上有索引)或row source已經在前面的步驟中被排序了。儘管合併兩個row source的過程是序列的,但是可以並行訪問這兩個row source(如並行讀入資料,並行排序)。
  SMJ連線的例子:
  SQL> explain plan for
  select/*+ ordered */e.deptno, d.deptno
  from emp e, dept d
  where e.deptno = d.deptno
  order by e.deptno, d.deptno;
  Query Plan
  -------------------------------------
  Select STATEMENT [CHOOSE] Cost=17
  MERGE JOIN
  SORT JOIN
  TABLE ACCESS FULL EMP [ANALYZED]
  SORT JOIN
  TABLE ACCESS FULL DEPT [ANALYZED]
  排序是一個費時、費資源的操作,特別對於大表。基於這個原因,SMJ經常不是一個特別有效的連線方法,但是如果2個row source都已經預先排序,則這種連線方法的效率也是蠻高的。
  2,巢狀迴圈(Nested Loops, NL)
  這個連線方法有驅動表(外部表)的概念。其實,該連線過程就是一個2層巢狀迴圈,所以外層迴圈的次數越少越好,這也就是我們為什麼將小表或返回較小 row source的表作為驅動表(用於外層迴圈)的理論依據。但是這個理論只是一般指導原則,因為遵循這個理論並不能總保證使語句產生的I/O次數最少。有時 不遵守這個理論依據,反而會獲得更好的效率。如果使用這種方法,決定使用哪個表作為驅動表很重要。有時如果驅動表選擇不正確,將會導致語句的效能很差、很差。
  內部連線過程:
  Row source1的Row 1 —— Probe ->Row source 2
  Row source1的Row 2 —— Probe ->Row source 2
  Row source1的Row 3 —— Probe ->Row source 2
  ……。
  Row source1的Row n —— Probe ->Row source 2
  從內部連線過程來看,需要用row source1中的每一行,去匹配row source2中的所有行,所以此時保持row source1儘可能的小與高效的訪問row source2(一般透過索引實現)是影響這個連線效率的關鍵問題。這只是理論指導原則,目的是使整個連線操作產生最少的物理I/O次數,而且如果遵守這 個原則,一般也會使總的物理I/O數最少。但是如果不遵從這個指導原則,反而能用更少的物理I/O實現連線操作,那儘管違反指導原則吧!因為最少的物理 I/O次數才是我們應該遵從的真正的指導原則,在後面的具體案例分析中就給出這樣的例子。
  在上面的連線過程中,我們稱Row source1為驅動表或外部表。Row Source2被稱為被探查表或內部表。
  在NESTED LOOPS連線中,Oracle讀取row source1中的每一行,然後在row sourc2中檢查是否有匹配的行,所有被匹配的行都被放到結果集中,然後處理row source1中的下一行。這個過程一直繼續,直到row source1中的所有行都被處理。這是從連線操作中可以得到第一個匹配行的最快的方法之一,這種型別的連線可以用在需要快速響應的語句中,以響應速度為 主要目標。
  如果driving row source(外部表)比較小,並且在inner row source(內部表)上有唯一索引,或有高選擇性非唯一索引時,使用這種方法可以得到較好的效率。NESTED LOOPS有其它連線方法沒有的的一個優點是:可以先返回已經連線的行,而不必等待所有的連線操作處理完才返回資料,這可以實現快速的響應時間。
  如果不使用並行操作,最好的驅動表是那些應用了where 限制條件後,可以返回較少行資料的的表,所以大表也可能稱為驅動表,關鍵看限制條件。對於並行查詢,我們經常選擇大表作為驅動表,因為大表可以充分利用並 行功能。當然,有時對查詢使用並行操作並不一定會比查詢不使用並行操作效率高,因為最後可能每個表只有很少的行符合限制條件,而且還要看你的硬體配置是否 可以支援並行(如是否有多個CPU,多個硬碟控制器),所以要具體問題具體對待。
  NL連線的例子:
  SQL> explain plan for
  select a.dname,b.sql
  from dept a,emp b
  where a.deptno = b.deptno;
  Query Plan
  -------------------------
  Select STATEMENT [CHOOSE] Cost=5
  NESTED LOOPS
  TABLE ACCESS FULL DEPT [ANALYZED]
  TABLE ACCESS FULL EMP [ANALYZED]
  3,雜湊連線(Hash Join, HJ)
  這種連線是在oracle 7.3以後引入的,從理論上來說比NL與SMJ更高效,而且只用在CBO最佳化器中。
  較小的row source被用來構建hash table與bitmap,第2個row source被用來被hansed,並與第一個row source生成的hash table進行匹配,以便進行進一步的連線。Bitmap被用來作為一種比較快的查詢方法,來檢查在hash table中是否有匹配的行。特別的,當hash table比較大而不能全部容納在記憶體中時,這種查詢方法更為有用。這種連線方法也有NL連線中所謂的驅動表的概念,被構建為hash table與bitmap的表為驅動表,當被構建的hash table與bitmap能被容納在記憶體中時,這種連線方式的效率極高。
  HASH連線的例子:
  SQL> explain plan for
  select/*+ use_hash(emp) */empno
  from emp, dept
  where emp.deptno = dept.deptno;
  Query Plan
  ----------------------------
  Select STATEMENT[CHOOSE] Cost=3
  HASH JOIN
  TABLE ACCESS FULL DEPT
  TABLE ACCESS FULL EMP
  要使雜湊連線有效,需要設定HASH_JOIN_ENABLED=TRUE,預設情況下該引數為TRUE,另外,不要忘了還要設定 hash_area_size引數,以使雜湊連線高效執行,因為雜湊連線會在該引數指定大小的記憶體中執行,過小的引數會使雜湊連線的效能比其他連線方式還 要低。
  另外,笛卡兒乘積(Cartesian Product)
  當兩個row source做連線,但是它們之間沒有關聯條件時,就會在兩個row source中做笛卡兒乘積,這通常由編寫程式碼疏漏造成(即程式設計師忘了寫關聯條件)。笛卡爾乘積是一個表的每一行依次與另一個表中的所有行匹配。在特殊情況下我們可以使用笛卡兒乘積,如在星形連線中,除此之外,我們要儘量不使用笛卡兒乘積,否則,自己想結果是什麼吧!
  注意在下面的語句中,在2個表之間沒有連線。
  SQL> explain plan for
  select emp.deptno,dept,deptno
  from emp,dept
  Query Plan
  ------------------------
  SLECT STATEMENT [CHOOSE] Cost=5
  MERGE JOIN CARTESIAN
  TABLE ACCESS FULL DEPT
  SORT JOIN
  TABLE ACCESS FULL EMP
  CARTESIAN關鍵字指出了在2個表之間做笛卡爾乘積。假如表emp有n行,dept表有m行,笛卡爾乘積的結果就是得到n * m行結果。
  最後,總結一下,在哪種情況下用哪種連線方法比較好:
  排序 - - 合併連線(Sort Merge Join, SMJ):
  a) 對於非等值連線,這種連線方式的效率是比較高的。
  b) 如果在關聯的列上都有索引,效果更好。
  c) 對於將2個較大的row source做連線,該連線方法比NL連線要好一些。
  d) 但是如果sort merge返回的row source過大,則又會導致使用過多的rowid在表中查詢資料時,資料庫效能下降,因為過多的I/O.
  巢狀迴圈(Nested Loops, NL):
  a) 如果driving row source(外部表)比較小,並且在inner row source(內部表)上有唯一索引,或有高選擇性非唯一索引時,使用這種方法可以得到較好的效率。
  b) NESTED LOOPS有其它連線方法沒有的的一個優點是:可以先返回已經連線的行,而不必等待所有的連線操作處理完才返回資料,這可以實現快速的響應時間。
  雜湊連線(Hash Join, HJ):
  a) 這種方法是在oracle7後來引入的,使用了比較先進的連線理論,一般來說,其效率應該好於其它2種連線,但是這種連線只能用在CBO最佳化器中,而且需要設定合適的hash_area_size引數,才能取得較好的效能。
  b) 在2個較大的row source之間連線時會取得相對較好的效率,在一個row source較小時則能取得更好的效率。
  c) 只能用於等值連線中
  +++
  Oracle執行計劃的概述
  ---
  Oracle執行計劃的相關概念:
  Rowid:系統給oracle資料的每行附加的一個偽列,包含資料表名稱,資料庫id,儲存資料庫id以及一個流水號等資訊,rowid在行的生命週期內唯一。
  Recursive sql:為了執行使用者語句,系統附加執行的額外操作語句,譬如對資料字典的維護等。
  Row source(行源):oracle執行步驟過程中,由上一個操作返回的符合條件的行的集合。
  Predicate(謂詞):where後的限制條件。
  Driving table(驅動表):又稱為連線的外層表,主要用於巢狀與hash連線中。一般來說是將應用限制條件後,返回較少行源的表作為驅動表。在後面的描述中,將driving table稱為連線操作的row source 1。
  Probed table(被探查表):連線的內層表,在我們從driving table得到具體的一行資料後,在probed table中尋找符合條件的行,所以該表應該為較大的row source,並且對應連線條件的列上應該有索引。在後面的描述中,一般將該表稱為連線操作的row source 2.
  Concatenated index(組合索引):一個索引如果由多列構成,那麼就稱為組合索引,組合索引的第一列為引導列,只有謂詞中包含引導列時,索引才可用。
  可選擇性:表中某列的不同數值數量/表的總行數如果接近於1,則列的可選擇性為高。
  Oracle訪問資料的存取方法:
  Full table scans, FTS(全表掃描):透過設定db_block_multiblock_read_count可以設定一次IO能讀取的資料塊個數,從而有效減少全表掃描時的IO總次數,也就是透過預讀機制將將要訪問的資料塊預先讀入記憶體中。只有在全表掃描情況下才能使用多塊讀操作。
  Table Access by rowed(透過rowid存取表,rowid lookup):由於rowid中記錄了行儲存的位置,所以這是oracle存取單行資料的最快方法。
  Index scan(索引掃描index lookup):在索引中,除了儲存每個索引的值外,索引還儲存具有此值的行對應的rowid值,索引掃描分兩步1,掃描索引得到rowid;2,透過 rowid讀取具體資料。每步都是單獨的一次IO,所以如果資料經限制條件過濾後的總量大於原表總行數的5%-10%,則使用索引掃描效率下降很多。而如果結果資料能夠全部在索引中找到,則可以避免第二步操作,從而加快檢索速度。
  根據索引型別與where限制條件的不同,有4種型別的索引掃描:
  Index unique scan(索引唯一掃描):存在unique或者primary key的情況下,返回單個rowid資料內容。
  Index range scan(索引範圍掃描):1,在唯一索引上使用了range運算子(>,,>=,<=,between);2,在組合索引上,只使用部分列進行查詢;3,對非唯一索引上的列進行的查詢。
  Index full scan(索引全掃描):需要查詢的資料從索引中可以全部得到。
  Index fast full scan(索引快速掃描):與index full scan類似,但是這種方式下不對結果進行排序。
  目前為止,典型的連線型別有3種:
  Sort merge join(SMJ排序-合併連線):首先生產driving table需要的資料,然後對這些資料按照連線操作關聯列進行排序;然後生產probed table需要的資料,然後對這些資料按照與driving table對應的連線操作列進行排序;最後兩邊已經排序的行被放在一起執行合併操作。排序是一個費時、費資源的操作,特別對於大表。所以smj通常不是一個特別有效的連線方法,但是如果driving table和probed table都已經預先排序,則這種連線方法的效率也比較高。
  Nested loops(NL巢狀迴圈):連線過程就是將driving table和probed table進行一次巢狀迴圈的過程。就是用driving table的每一行去匹配probed table 的所有行。Nested loops可以先返回已經連線的行,而不必等待所有的連線操作處理完成才返回資料,這可以實現快速的響應時間。
  Hash join(雜湊連線):較小的row source被用來構建hash table與bitmap,第二個row source用來被hashed,並與第一個row source生產的hash table進行匹配。以便進行進一步的連線。當被構建的hash table與bitmap能被容納在記憶體中時,這種連線方式的效率極高。但需要設定合適的hash_area_size引數且只能用於等值連線中。
  另外,還有一種連線型別:Cartesian product(笛卡爾積):表的每一行依次與另外一表的所有行匹配,一般情況下,儘量避免使用。

日常開發活動中,有時候需要對oracle執行計劃進行監控,以此來調優程式和資料庫方面的效能。
常用方法有以下幾種:
一、透過PL/SQL Dev工具
    1、直接File->New->Explain Plan Window,在視窗中執行sql可以檢視計劃結果。其中,Cost表示cpu的消耗,單位為n%,Cardinality表示執行的行數,等價Rows。
    2、先執行 EXPLAIN PLAN FOR   select * from tableA where paraA=1,再 select * from table(DBMS_XPLAN.DISPLAY)便可以看到oracle的執行計劃了,看到的結果和1中的一樣,所以使用工具的時候推薦使用1方法。
注意:PL/SQL Dev工具的Command window中不支援set autotrance on的命令。還有使用工具方法檢視計劃看到的資訊不全,有些時候我們需要sqlplus的支援。

二、透過sqlplus
    1、一般情況都是本機連結遠端伺服器,所以命令如下:
            sqlplus user/pwd@serviceName
        此處的serviceName為tnsnames.ora中定義的名稱空間。
    2、執行set autotrace on,然後執行sql語句,會列出以下資訊:
    
。。。(省略一些資訊)
統計資訊
----------------------------------------------------------
          1  recursive calls (歸呼叫次數)
          0  db block gets  
          2  consistent gets
          0  physical reads (物理讀——執行SQL的過程中,從硬碟上讀取的資料塊個數)
          0  redo size (重做數——執行SQL的過程中,產生的重做日誌的大小)
        358  bytes sent via SQL*Net to client
        366  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)     在記憶體中發生的排序
          0  sorts (disk)     在硬碟中發生的排序
          1  rows processed
省略部分資訊和透過PL/SQL Dev工具檢視執行計劃的資訊一樣,下面的統計資訊是更詳細的。
判斷SQL效率高低不關透過時間來衡量,還應該透過執行SQL執行狀態裡面的邏輯讀的數量
    邏輯讀=(db block gets+ consistent gets)

=================================================================================================


基於ORACLE的應用系統很多效能問題,是由應用系統SQL效能低劣引起的,所以,SQL的效能最佳化很重要,分析與最佳化SQL的效能我們一般透過檢視該SQL的執行計劃,本文就如何看懂執行計劃,以及如何透過分析執行計劃對SQL進行最佳化做相應說明。
一、什麼是執行計劃(explain plan)
執行計劃:一條查詢語句在ORACLE中的執行過程或訪問路徑的描述。
二、如何檢視執行計劃
1: 在PL/SQL下按F5檢視執行計劃。第三方工具toad等。
很多人以為PL/SQL的執行計劃只能看到基數、最佳化器、耗費等基本資訊,其實這個可以在PL/SQL工具裡面設定的。可以看到很多其它資訊,如下所示
clip_image002
2: 在SQL*PLUS(PL/SQL的命令視窗和SQL視窗均可)下執行下面步驟

SQL>EXPLAIN PLAN FOR
          Select * FROM SCOTT.EMP;  --要解析的SQL指令碼
SQL>Select * FROM TABLE(DBMS_XPLAN.DISPLAY);


clip_image004
clip_image006
3: 在SQL*PLUS下(有些命令在PL/SQL下無效)執行如下命令:

SQL>SET TIMING ON             --控制顯示執行時間統計資料

SQL>SET AUTOTRACE ON EXPLAIN       --這樣設定包含執行計劃、指令碼資料輸出,沒有統計資訊

SQL>執行需要檢視執行計劃的SQL語句

SQL>SET AUTOTRACE OFF           --不生成AUTOTRACE報告,這是預設模式

SQL> SET AUTOTRACE ON           --這樣設定包含執行計劃、統計資訊、以及指令碼資料輸出

SQL>執行需要檢視執行計劃的SQL語句

SQL>SET AUTOTRACE OFF

SQL> SET AUTOTRACE TRACEONLY      --這樣設定會有執行計劃、統計資訊,不會有指令碼資料輸出

SQL>執行需要檢視執行計劃的SQL語句

SQL>SET AUTOTRACE TRACEONLY STAT     --這樣設定只包含有統計資訊

SQL>執行需要檢視執行計劃的SQL語句

SET AUTOT[RACE] {ON | OFF | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
參考文件:SQLPlus User’s Guide and Reference Release 11.1
clip_image008
注意:PL/SQL Developer 工具並不完全支援所有的SQL*Plus命令,像SET AUTOTRACE ON 就如此,在PL/SQL Developer工具下執行此命令會報錯
SQL> SET AUTOTRACE ON;
Cannot SET AUTOTRACE
4:SQL_TRACE可以作為引數在全域性啟用,也可以透過命令形式在具體SESSION啟用
4.1 在全域性啟用,在引數檔案(pfile/spfile)中指定SQL_TRACE =true,在全域性啟用SQL_TRACE時會導致所有程式活動被跟蹤,包括後臺程式以及使用者程式,通常會導致比較嚴重的效能問題,所以在生產環境要謹慎使用。
提示:透過在全域性啟用SQL_TRACE, 我們可以跟蹤到所有後臺程式的活動,很多在文件中的抽象說明,透過跟蹤檔案的實時變化,我們可以清晰的看到各個程式間的緊密協調。
4.2在當前SESSION級別設定,透過跟蹤當前程式可以發現當前操作的後臺資料庫遞迴活動(這在研究資料庫新特性時尤其有效),研究SQL執行時,發現後臺
錯誤等。

SQL> Alter SESSION SET SQL_TRACE=TRUE;

SQL> Select * FROM SCOTT.EMP;

SQL> Alter SESSION SET SQL_TRACE =FALSE;

那麼此時如何檢視相關資訊?不管你在SQL*PLUS抑或PL/SQL DEVELOPER工具裡面執行上面指令碼過後都看不到什麼資訊,你可以透過下面指令碼查詢到trace日誌資訊

Select T.VALUE || '/' || LOWER(RTRIM(I.INSTANCE, CHR(0))) || '_ora_' ||

P.SPID || '.trc' TRACE_FILE_NAME

FROM

( Select P.SPID

FROM V$MYSTAT M, V$SESSION S, V$PROCESS P

Where M.STATISTIC# =1

AND S.SID = M.SID

AND P.ADDR = S.PADDR

) P,

( Select T.INSTANCE

FROM V$THREAD T, V$PARAMETER V

Where V.NAME ='thread'

AND (V.VALUE = 0 or T.THREAD# = TO_NUMBER(V.VALUE))

) I,

(Select VALUE FROM V$PARAMETER Where NAME='user_dump_dest') T



clip_image010
TKPROF的幫助資訊如下

TKPROF 選項   
選項                                          說明  
TRACEFILE                               跟蹤輸出檔案的名稱  
OUTPUTFILE                              已設定格式的檔案的名稱  
SORT=option                             語句的排序順序  
PRINT=n                                 列印前 n 個語句  
EXPLAIN=user/password                   以指定的使用者名稱執行 EXPLAIN PLAN  
Insert=filename                         生成 Insert 語句  
SYS=NO                                  忽略作為使用者 sys 執行的遞迴 SQL 語句  
AGGREGATE=[Y|N]                         如果指定 AGGREGATE = NO TKPROF 不聚集相同   
                                        SQL 文字的多個使用者  
RECORD=filename                         記錄在跟蹤檔案中發現的語句  
TABLE=schema.tablename                  將執行計劃放入指定的表而不是預設的PLAN_TABLE   
    
可以在作業系統中鍵入 tkprof 以獲得所有可用選項和輸出的列表  
注 排序選項有   
    
排序                                    選項說明  
prscnt execnt fchcnt             呼叫分析執行提取的次數  
prscpu execpu fchcpu             分析執行提取所佔用的 CPU 時間  
prsela exela fchela              分析執行提取所佔用的時間  
prsdsk exedsk fchdsk             分析執行提取期間的磁碟讀取次數  
prsqry exeqry fchqry             分析執行提取期間用於持續讀取的緩衝區數  
prscu execu fchcu                分析執行提取期間用於當前讀取的緩衝區數  
prsmis exemis                    分析執行期間庫快取記憶體未命中的次數  
exerow fchrow                    分析執行期間處理的行數  
userid                           分析遊標的使用者的使用者 ID   
    
TKPROF 統計資料  
Count: 執行呼叫數  
CPU: CPU 的使用秒數  
Elapsed: 總共用去的時間  
Disk: 物理讀取次數  
Query: 持續讀取的邏輯讀取數  
Current: 當前模式下的邏輯讀取數  
Rows: 已處理行數   
TKPROF 統計資訊   
統計             含義  
Count     分析或執行語句的次數以及為語句發出的提取呼叫數  
CPU       每個階段的處理時間以秒為單位如果在共享池中找到該語句對於分析階段為 0  
Elapsed   佔用時間以秒為單位通常不是非常有用因為其它程式影響佔用時間  
Disk      從資料庫檔案讀取的物理資料塊如果該資料被緩衝則該統計可能很低  
Query     為持續讀取檢索的邏輯緩衝區通常用於 Select 語句  
Current   在當前模式下檢索的邏輯緩衝區通常用於 DML 語句   
Rows      外部語句所處理的行對於 Select 語句在提取階段顯示它對於 DML 語句在執行階段顯示它   
    
Query 和Current 的總和為所訪問的邏輯緩衝區的總數 

執行下面命令:tkprof D:\ORACLE\PRODUCT\10.2.0\DB_1\RDBMS\TRACE/wgods_ora_3940.trc h:\out.txtoutputfile explain=etl/etl
clip_image012
執行上面命令後,可以檢視生成的文字檔案
View Code
TKPROF: Release 10.2.0.1.0 - Production on 星期三 5月 23 16:56:41 2012

Copyright (c) 1982, 2005, oracle.  All rights reserved.

Trace file: D:\ORACLE\PRODUCT\10.2.0\DB_1\RDBMS\TRACE/wgods_ora_3940.trc
Sort options: default

********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing 
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************

Alter SESSION SET SQL_TRACE = TRUE


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        1      0.00       0.00          0          0          0           0

Misses in library cache during parse: 0
Misses in library cache during execute: 1
Optimizer mode: CHOOSE
Parsing user id: 89  (ETL)
********************************************************************************

begin :id := sys.dbms_transaction.local_transaction_id; end;


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          0          0           0
Execute      2      0.00       0.00          0          0          0           2
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0          0          0           2

Misses in library cache during parse: 0
Optimizer mode: CHOOSE
Parsing user id: 89  (ETL)
********************************************************************************

Select * 
FROM
SCOTT.EMP


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        1      0.00       0.00          0          7          0          14
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.00       0.00          0          7          0          14

Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: 89  (ETL)

Rows     Execution Plan
-------  ---------------------------------------------------
      0  Select STATEMENT   MODE: CHOOSE
      0   TABLE ACCESS   MODE: ANALYZED (FULL) OF 'EMP' (TABLE)

********************************************************************************

Alter SESSION SET SQL_TRACE = FALSE


call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.00       0.00          0          0          0           0

Misses in library cache during parse: 1
Optimizer mode: CHOOSE
Parsing user id: 89  (ETL)



********************************************************************************

OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        5      0.00       0.00          0          0          0           0
Execute      5      0.00       0.00          0          0          0           2
Fetch        1      0.00       0.00          0          7          0          14
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       11      0.00       0.00          0          7          0          16

Misses in library cache during parse: 2
Misses in library cache during execute: 1


OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        0      0.00       0.00          0          0          0           0
Execute      0      0.00       0.00          0          0          0           0
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        0      0.00       0.00          0          0          0           0

Misses in library cache during parse: 0

    6  user  SQL statements in session.
    0  internal SQL statements in session.
    6  SQL statements in session.
    1  statement EXPLAINed in this session.
********************************************************************************
Trace file: D:\ORACLE\PRODUCT\10.2.0\DB_1\RDBMS\TRACE/wgods_ora_3940.trc
Trace file compatibility: 10.01.00
Sort options: default

       1  session in tracefile.
       6  user  SQL statements in trace file.
       0  internal SQL statements in trace file.
       6  SQL statements in trace file.
       4  unique SQL statements in trace file.
       1  SQL statements EXPLAINed using schema:
           ETL.prof$plan_table
             Default table was used.
             Table was created.
             Table was dropped.
      58  lines in trace file.
       0  elapsed seconds in trace file.

4.3跟蹤其它使用者的程式,在很多時候我們需要跟蹤其它使用者的程式,而不是當前使用者,可以透過ORACLE提供的系統包
DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION來完成。
例如:

Select SID, SERIAL#, USERNAME FROM V$SESSION Where USERNAME = 'ETL'

EXEC DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(61,76,TRUE);

EXEC DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(61,76,FALSE);



5 利用10046事件
Alter SESSION SET TRACEFILE_IDENTIFIER = 10046;

Alter SESSION SET EVENTS='10046 trace name context forever, level 8';

Select * FROM SCOTT.EMP;

Alter SESSION SET EVENTS ='10046 trace name context off';

然後你可以用指令碼檢視追蹤檔案的位置

Select T.VALUE || '/' || LOWER(RTRIM(I.INSTANCE, CHR(0))) || '_ora_' ||

P.SPID || '.trc' TRACE_FILE_NAME

FROM

( Select P.SPID

FROM V$MYSTAT M, V$SESSION S, V$PROCESS P

Where M.STATISTIC# =1

AND S.SID = M.SID

AND P.ADDR = S.PADDR

) P,

( Select T.INSTANCE

FROM V$THREAD T, V$PARAMETER V

Where V.NAME ='thread'

AND (V.VALUE = 0 or T.THREAD# = TO_NUMBER(V.VALUE))

) I,

(Select VALUE FROM V$PARAMETER Where NAME='user_dump_dest') T

查詢結果為wgods_ora_28279.trc檔案, 但是去相應目錄卻沒有找到對應的追蹤檔案,而是如下trace檔案:wgods_ora_28279_10046.trc


6 利用10053事件
  有點類似10046,在此略過、
7 系統檢視
透過下面一些系統檢視,你可以看到一些零散的執行計劃的相關資訊,有興趣的話可以多去研究一下。

Select * FROM V$SQL_PLAN

Select * FROM V$RSRC_PLAN_CPU_MTH

Select * FROM V$SQL_PLAN_STATISTICS

Select * FROM V$SQL_PLAN_STATISTICS_ALL

Select * FROM V$SQLAREA_PLAN_HASH

Select * FROM V$RSRC_PLAN_HISTORY


三、看懂執行計劃
1.執行順序
執行順序的原則是:由上至下,從右向左
由上至下:在執行計劃中一般含有多個節點,相同級別(或並列)的節點,靠上的優先執行,靠下的後執行
從右向左:在某個節點下還存在多個子節點,先從最靠右的子節點開始執行。
當然,你在PL/SQL工具中也可以透過它提供的功能來檢視執行順序。如下圖所示:
clip_image014
2.執行計劃中欄位解釋
clip_image016
SQL>
名詞解釋:
recursive calls           遞迴呼叫
db block gets           從buffer cache中讀取的block的數量當前請求的塊數目,當前模式塊意思就是在操作中正好提取的塊數目,而不是在一致性讀的情況下而產生的正常情況下,一個查詢提取的塊是在查詢查詢開始的那個時間點上存在的資料庫,當前塊是在這個時候存在資料塊,而不是這個時間點之前或者之後的的資料塊數目。
consistent gets          從buffer cache中讀取的undo資料的block的數量資料請求總數在回滾段Buffer中的資料一致性讀所需要的資料塊,,這裡的概念是在你處理你這個操作的時侯需要在一致性讀狀態上處理多個塊,這些塊產生的主要原因是因為你在查詢過程中,由於其它會話對資料 塊進行操作,而對所要查詢的塊有了修改,但是由於我們的查詢是在這些修改之前呼叫的,所要需要對回滾 段中的資料塊的前映像進行查詢,以保證資料的一致性。這樣就產生了一致性讀。

physical reads           物理讀 就是從磁碟上讀取資料塊的數量。其產生的主要原因是:
                  1:在資料庫快取記憶體中不存在這些塊。
                  2:全表掃描
                  3:磁碟排序
redo size              DML生成的redo的大小
sorts (memory)           在記憶體執行的排序量
sorts (disk)             在磁碟執行的排序量
2091 bytes sent via SQL*Net to client     從SQL*Net向客戶端傳送了2091位元組的資料
416 bytes received via SQL*Net from client  客戶端向SQL*Net傳送了416位元組的資料。
參考文件:SQLPlus User’s Guide and Reference Release 11.1
clip_image018
db block gets 、 consistent gets 、 physical reads這三者的關係可以概括為:邏輯讀指的是ORACLE從記憶體讀到的資料塊塊數量,一般來說是:
consistent gets + db block gets. 當在記憶體中找不到所需要的資料塊的話,就需要從磁碟中獲取,於是就產生了物理讀。
3.具體內容檢視
1> Plan hash Value
這一行是這一條語句的的hash值,我們知道ORACLE對每一條ORACLE語句產生的執行計劃放在SHARE POOL裡面,第一次要經過硬解析,產生hash值。下次再執行時比較hash值,如果相同就不會執行硬解析。
2> COST

COST沒有單位,是一個相對值,是SQL以CBO方式解析執行計劃時,供ORACLE來評估CBO成本,選擇執行計劃用的。沒有明確的含義,但是在對比是就非常有用。
公式:COST=(Single Block I/O COST + MultiBlock I/O Cost + CPU Cost)/ Sreadtim

3> 對上面執行計劃列欄位的解釋:
Id: 執行序列,但不是執行的先後順序。執行的先後根據Operation縮排來判斷(採用最右最上最先執行的原則看層次關係,在同一級如果某個動作沒有子ID就最先執行。一般按縮排長度來判斷,縮排最大的最先執行,如果有2行縮排一樣,那麼就先執行上面的。)
    Operation:當前操作的內容。
    Name:操作物件
    Rows:也就是10g版本以前的Cardinality(基數),Oracle估計當前操作的返回結果集行數。
    Bytes:表示執行該步驟後返回的位元組數。
    Cost(CPU):表示執行到該步驟的一個執行成本,用於說明SQL執行的代價。
    Time:Oracle 估計當前操作的時間。
4.謂詞說明:
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("B"."MGR" IS NOT NULL)
4 - access("A"."EMPNO" = "B"."MGR")
    Access: 表示這個謂詞條件的值將會影響資料的訪問路勁(全表掃描還是索引)。
    Filter:表示謂詞條件的值不會影響資料的訪問路勁,只起過濾的作用。
    在謂詞中主要注意access,要考慮謂詞的條件,使用的訪問路徑是否正確。
5、 動態分析
如果在執行計劃中有如下提示:
Note
------------
-dynamic sampling used for the statement
這提示使用者CBO當前使用的技術,需要使用者在分析計劃時考慮到這些因素。 當出現這個提示,說明當前表使用了動態取樣。我們從而推斷這個表可能沒有做過分析。
這裡會出現兩種情況:
(1) 如果表沒有做過分析,那麼CBO可以透過動態取樣的方式來獲取分析資料,也可以或者正確的執行計劃。
(2) 如果表分析過,但是分析資訊過舊,這時CBO就不會在使用動態取樣,而是使用這些舊的分析資料,從而可能導致錯誤的執行計劃。
四、表訪問方式
1.Full Table Scan (FTS) 全表掃描

2.Index Lookup 索引掃描
There are 5 methods of index lookup:
index unique scan --索引唯一掃描
透過唯一索引查詢一個數值經常返回單個ROWID,如果存在UNIQUE或PRIMARY KEY約束(它保證了語句只存取單行的話),ORACLE
經常實現唯一性掃描
Method for looking up a single key value via a unique index. always returns a single value, You must supply AT LEAST the leading column of the index to access data via the index.
index range scan --索引區域性掃描
Index range scan is a method for accessing a range values of a particular column. AT LEAST the leading column of the index must be supplied to access data via the index. Can be used for range operations (e.g. > < <> >= <= between) .
使用一個索引存取多行資料,在唯一索引上使用索引範圍掃描的典型情況是在謂詞(Where 限制條件)中使用了範圍運算子號(如>, < <>, >=, <=,BWTEEN)
index full scan --索引全域性掃描
Full index scans are only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort. For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order.
index fast full scan --索引快速全域性掃描,不帶order by情況下常發生
Scans all the block in the index, Rows are not returned in sorted order, Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO, may be hinted using INDEX_FFS hint, uses multiblock i/o, can be executed in parallel, can be used to access second column of concatenated indexes. This is because we are selecting all of the index.
index skip scan --索引跳躍掃描,where條件列是非索引的前提情況下常發生
Index skip scan finds rows even if the column is not the leading column of a concatenated index. It skips the first column(s) during the search.
3.Rowid 物理ID掃描
This is the quickest access method available.Oracle retrieves the specified block and extracts the rows it is interested in. --Rowid掃描是最快的訪問資料方式 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23490154/viewspace-1396006/,如需轉載,請註明出處,否則將追究法律責任。

相關文章