簡介:
本文全面詳細介紹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)
3、表之間的鏈接
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]
3、表之間的鏈接
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(笛卡爾積):表的每一行依次與另一表的全部行匹配,通常狀況下,儘可能避免使用。