您正在看的ORACLE教程是:Oracle數據庫執行計劃的一些基本概念 (1)。
一.相關的概念
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 DUAL2) 通過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%,使用索引掃描會效率下降很