Oracle優化-Oracle訪問資料的幾種方式
ORACLE如何訪問資料1.全表掃描(FullTableScansFTS)為實現全表掃描,
Oracle讀取表中所有行,並檢查每一行是否滿足語句的WHERE限制條件一個多塊讀操作可以使一次I/O能讀取多塊資料塊(db_block_multiblock_read_count引數設定),
而不是隻讀取一個數據塊, 這極大的減
少了I/O總次數,
提高了系統的吞吐量,所以利用多塊讀的方法可以十分高效地實現全表掃描,而且只有在全表掃描的情況下才能使用多塊讀操作。在這種訪問模式下,每個資料塊只被讀一次。使用FTS的前提條件:在較大的表上不建議使用全表掃描,除非取出資料的比較多,超過總量的5%——10%,或你想使用並行查詢功能時。
Example:SQL>explainplanforselect*fromdual;QueryPlan-----------------------------------------SELECTSTATEMENT[CHOOSE]Cost=TABLEACCESSFULLDUAL全表掃描模式下會讀資料到表的高水位線(
HWM即表示表曾經擴充套件的最後一個數據塊),讀取速度依賴於Oracle初始化引數db_block_multiblock_read_count(FTS掃描會使表使用上升到高水位(HWM),HWM標識了表最後寫入資料的塊,如果你用DELETE刪除了所有的資料表仍然處於高水位
QueryPlan------------------------------------SELECTSTATEMENT[CHOOSE]Cost=1**INDEXUNIQUESCANEMP_I1 --如果索引裡就找到了所要的資料,就不會再去訪問表通過設定db_block_multiblock_read_count可以設定一次IO能讀取的資料塊個數, 從而有效減少全表掃描時的IO總次數, 也就是通過預讀機制將將要訪問的資料塊預先讀入記憶體中。只有在全表掃描情況下才能使用多塊讀操作。
2.通過ROWID的表存取(
SQL>explainplanforselect*fromdeptwhererowid=''AAAAyGAADAAAAATAAF'';QueryPlan------------------------------------SELECTSTATEMENT[CHOOSE]Cost=1TABLEACCESSBYROWIDDEPT[ANALYZED]
3. 索引掃描(IndexScan或indexlookup)
我們先通過index查詢到資料對應的rowid值 ( 對於非唯一索引可能返回多個rowid值),然後根據rowid直接從表中得到具體的資料,這種查詢方式稱為索引掃描或索引查詢 ( indexlookup)。 一個 rowid唯一的表示一行資料, 該行對應的資料塊是通過一次 I/0得到的, 在此情況下該次 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=1TABLE 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=1INDEX UNIQUE SCAN EMP_I1進一步講, 如果 sql語句中對索引列進行排序, 因為索引已經預先排序好了, 所以在執行計劃中不需要再對索引列進行排序SQL> explain plan for select empno, ename from emp where empno > 7876order by empno;Query Plan--------------------------------------------------------------------------------SELECT STATEMENT[CHOOSE] Cost=1TABLE ACCESS BY ROWID EMP [ANALYZED]INDEX RANGE SCAN EMP_I1 [ANALYZED]從這個例子中可以看到: 因為索引是已經排序了的, 所以將按照索引的順序查詢出符合條件的行,因此避免了進一步排序操作。根據索引的型別與 where限制條件的不同,有 4種類型的索引掃描:
1) 索引唯一掃描(index unique scan)通過唯一索引查詢一個數值經常返回單個ROWID.如果存在 UNIQUE 或 PRIMARYKEY 約束(它保證了語句只存取單行)的話, Oracle經常實現唯一性掃描。使用唯一性約束的例子:SQL> explain plan for select empno, enamefrom empwhere empno=10;Query Plan------------------------------------SELECTSTATEMENT[CHOOSE] Cost=1TABLEACCESS BYROWID EMP [ANALYZED]INDEX UNIQUE SCAN EMP_I12) 索引範圍掃描(index range scan)使用一個索引存取多行資料,在唯一索引上使用索引範圍掃描的典型情況下是在謂詞( where限制條件)中使用了範圍操作符(如>、 <、 <>、 >=、 <=、 between)使用索引範圍掃描的例子:SQL> explain plan for select empno, ename from emp where empno > 7876orderby empno;Query Plan--------------------------------------------------------------------------------SELECTSTATEMENT[CHOOSE] Cost=1TABLEACCESS BYROWID EMP [ANALYZED]INDEX RANGE SCAN EMP_I1 [ANALYZED]在非唯一索引上,謂詞col = 5可能返回多行資料,所以在非唯一索引上都使用索引範圍掃描。使用index rang scan的3種情況:1 在唯一索引列上使用了range操作符( > < <> >= <= between)2 在組合索引上,只使用部分列進行查詢,導致查詢出多行3 對非唯一索引列上進行的任何查詢。3) 索引全掃描(index full scan)與全表掃描對應, 也有相應的全索引掃描。而且此時查詢出的資料都必須從索引中可以直接得到。全索引掃描的例子:SQL>explain planforselectempno, enamefrombig_emporderbyempno,ename;Query Plan--------------------------------------------------------------------------------SELECTSTATEMENT[CHOOSE] Cost=26INDEX FULLSCAN BE_IX [ANALYZED]4) 索引快速掃描(index fastfull 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=1INDEX FAST FULLSCAN BE_IX [ANALYZED]只選擇多列索引的第2列:SQL> explain plan for select ename from big_emp;Query Plan------------------------------------------SELECT STATEMENT[CHOOSE] Cost=1INDEX FAST FULLSCAN BE_IX [ANALYZED]