這里,我學到的一個很重要的東西,就是用PL/SQL DEVELOPER去看一條SELECT語句的執行計划,執行計划里面可以看到這條SELECT語句的開銷、I/O操作開銷等數值,可以很清晰地看到語句各個部分的執行效率。選中這條SELECT語句以后,按F5就可以。
以下面的SELECT語句為例子:
從三張表中取數據,按我以前的想法,只要WHERE語句那里有能讓三張表連接起來的條件就可以。所以我只使用了:

按F5后,可以看到這樣做的執行計划如下:

修改后的SELECT語句如下:


執行計划的執行順序是,從內層至外層,從上往下。比如上面修改后的實行計划中,數據庫先對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的優化相當神奇,效果是一樣的,但只是加一個條件就可以使得執行效率有如此大的提高。就這個改變,使得彈出來的超時提醒的幾率大大降低,對於用戶來說這個改變是很重要的。
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;