這裏,我學到的一個很重要的東西,就是用PL/SQL DEVELOPER去看一條SELECT語句的執行計劃,執行計劃裏面可以看到這條SELECT語句的開銷、I/O操作開銷等數值,可以很清晰地看到語句各個部分的執行效率。選中這條SELECT語句以後,按F5就可以。
以下面的SELECT語句爲例子:
從三張表中取數據,按我以前的想法,只要WHERE語句那裏有能讓三張表連接起來的條件就可以。所以我只使用了:
按F5後,可以看到這樣做的執行計劃如下:
開銷974,其實並不算高。但是加上測試環境的數據庫連接速度確實很慢,導致了經常會出現數據庫連接超時的提示。
修改後的SELECT語句如下:
可以看到,修改只是在WHERE裏面多加了兩個關聯條件。此時再按F5看執行計劃:
這時候COST只剩下95了。實際操作中,確實也明顯感到了操作速度的提升。
執行計劃的執行順序是,從內層至外層,從上往下。比如上面修改後的實行計劃中,數據庫先對ORDER_HEADER的主鍵做了一個索引範圍檢索,然後再對XXWMS_DLX_SERIAL_NUMBER的非唯一性索引XXWMS_DLX_SERIAL_NUMBER_N4做索引範圍檢索。
在做修改之前,SERIAL_NUMBER表和XXWMS_DLX_SERIAL_NUMBER表使用了循環嵌套(NESTED LOOPS)的連接方法,得到結果後再與ORDER_HEADER進行哈希連接。由於兩個表的數據量都比較大(SERIAL_NUMBER在測試環境中數據量達到一千四百萬條左右),循環嵌套連接的步驟顯然開銷了很多。
可以猜想,如果循環嵌套連接中其中一個表的數據量小一點,就可以減少很多開銷。於是,在連接條件中多加一條xx.client_id = oh.client_id。這樣就使用了ORDER_HEADER的主鍵去和XXWMS_DLX_SERIAL_NUMBER的N4索引進行連接,得到結果以後再去和SERIAL_NUMBER連接。結果在上圖可以看到,COST只有95,大大加快了執行的效率。
這個經歷讓我覺得PL/SQL的優化相當神奇,效果是一樣的,但只是加一個條件就可以使得執行效率有如此大的提高。就這個改變,使得彈出來的超時提醒的機率大大降低,對於用戶來說這個改變是很重要的。
其它查看方法:
需要先創建plan_table
create table PLAN_TABLE (
statement_id varchar2(30),
timestamp date,
remarks varchar2(80),
operation varchar2(30),
options varchar2(255),
object_node varchar2(128),
object_owner varchar2(30),
object_name varchar2(30),
object_instance numeric,
object_type varchar2(30),
optimizer varchar2(255),
search_columns number,
id numeric,
parent_id numeric,
position numeric,
cost numeric,
cardinality numeric,
bytes numeric,
other_tag varchar2(255),
partition_start varchar2(255),
partition_stop varchar2(255),
partition_id numeric,
other long,
distribution varchar2(30),
cpu_cost numeric,
io_cost numeric,
temp_space numeric);
建表的sql在rdbms/admin下有,名字是utlxplan.sql
我用的是9i,其他版本的名字可能不一樣,
然後執行
explain plan for sql語句
然後可以執行這個sql看結果
SELECT LPAD (' ', 2 * LEVEL) ||
operation ||
' ' ||
options ||
' ' ||
object_name query_plan
FROM plan_table
CONNECT BY PRIOR id = parent_id
START WITH id = 1
ORDER BY id;
另摘:
執行後下面有一些信息,看cost列,一般越小效率越高,還有看Description列,有沒有table access full 這種全表掃描標誌的,一般查詢大表要避免全表掃描。