SQL和PL/SQL的效能優化之二--執行計劃管理
1、提示--它們僅是建議,優化器可以選擇忽略他們。事實上,優化器將盡可能地遵從優化提示,哪怕會導致空難性的效能影響。一般來說,只有當你用盡非直接方法(收集統計資訊,建立柱狀圖及設定配置引數等)之後,才可以考慮使用提示。
下面是一些更常見的提示:
ALL_ROWS 使用ALL_ROWS優化器目標
AND_EQUALS(表名... 索引名 索引名 ···) 合併指定索引來提取指定的表的記錄,與下一個類似,但是不使用企業版才支援的位置轉換策略。
INDEX_COMBINE(表名,索引名 索引名···) 與上面的類似,但是使用只有在企業版中才有的位置轉換策略
APPEND 使用直接模式插入
CACHE(表名) 當執行全表掃描操作時,促進表在ORACLE共享記憶體中的快取(NOCACHE反效)
FACT(表名) 考慮使用指定的表作為星型模式的事實表
FIRST_ROWS(N) 使用FIRST_ROWS優化器目標
FULL(表名)
HASH(表名) 對指定的表使用基於雜湊聚簇的訪問方式(顯然,只有與表是雜湊聚簇表時才有效)
INDEX(表名[索引名]) 使用指定表上的指定索引。如果沒指定索引,則使用表上帶來最低開銷的那個索引
INDEX_SS(表名 索此名) 使用索引“跳躍掃描”訪問路徑
LEADING(表名···) 指定表作為聯結順序中驅動表,並指定順序進行連線
PARALLEL(表名並行度) NOPARALLED
ORDERED 使用FROM子句中表出現的順序作為聯結的順序,它將覆寫普通的基於成本計算得出來的聯結順序
USE_HASH(表名) 雜湊聯結技術
USE_MERGE(表名) 排序合併方法
USE_NL(表名) 巢狀迴圈方法
2、儲存提綱:是在特定的時間點為特定的SQL語句記錄執行計劃的方法。然後你可以啟用儲存提綱以保證即使統計資訊在未來發生改變,特定的執行計劃依然會被使用。
儲存提綱將被SQL計劃基線取代,但10G,11G標準版完全支援儲存提綱
建立儲存提綱:
Create outline customer_yob_qry for category outlines2 on
select max(cust_income_level)
from customers c
where cust_year_of_birth >1985;
每個儲存提綱都屬於一個特定的類目;上面的類目OUTLINES2,可以在會話級或系統級使用引數USE_STORED_OUTLINES來啟用。
ALTER SESSION SET USE_STORED_OUTLINES=OUTLINES2;
侵入儲存提綱:
不能編輯SQL語句的情況下,強制SQL採用另一個不同的計劃。
A>首先我們對未改變的SQL語句建立一個儲存提綱;
Create outline customer_yob_otln for category outlines2 on
select min(cust_income_level)
from customers c
where cust_year_of_birth >1985;
B>我們由公共儲存提綱建立一個私有儲存提綱
Create Private outline original_oln from cust_yob_otln;
C>現在我們建立一個擁有相同SQL語句但包含任何我們想指定的提示;
Create private outline hinted_oln on
select /*+ index(c)*/ min(cust_income_level)
from customers c
where cust_year_of_birth>1985;
查詢全域性臨時表ol$hints(它擁有私有儲存提綱的定義),可以看到應用於每個儲存提綱的提示,注意到original_oln有一個FULL提示,而hinted_oln有一個index提示。
select on_name,hint_text from ol$hints;
D>我們現在想做的是將HINTED_OLN中的提示覆制到ORIGINAL_OLN中。ol$hints表包含提示的內容,而它的父表,ol$包含提示的數量,它也必須被更新。
下面的SQL語句交換儲存提綱:
update ol$hints
set ol_name = case ol_name
when 'HINTED_OLN'
then 'ORIGINAL_OLN'
when 'ORIGINAL_OLN'
then 'HINTED_OLN'
else ol_name
end
where ol_name in('HINTED_OLN','ORIGINAL_OLN');
update ol$ ol2
set hintcount=(select hintcount from ol$ ol2
where ol2.ol_name in('HINTED_OLN','ORIGINAL_OLN')
and ol2.ol_name != ol1.ol_name)
where ol1.ol_name in('HINTED_OLN','ORIGINAL_OLN');
現在,啟用私有儲存提綱,可以看到原始SQL語句成功強制使用了索引
ALTER SESSION SET USE_PRIVATE_OUTLINES=TRUE;
E>最後,我們要做的事就是把私有儲存提綱複製回原有的公有儲存提綱裡。
Create or replace outline cust_yob_otln from
private original_oln for category outlines2;
現在,如果激活了儲存提綱類目OUTLINES2,SQL語句將會使用索引,就如其中包含了索引提示一樣。
3、SQL概要--為增加優化器的靈活性,當環境變化時,為新的SQL建立更優執行計劃的能力,SQL概要及相關的SQL調優顧問是10G引入的,需ORACLE調優包授權許可。
SQL概要是一個由SQL調優任務建立的與該SQL相關的特定統計資訊的集合,它可以在隨後被SQL調優顧問用來決定一個最優的計劃,調優顧問可理解為一個離線優化器(offline optimizer)
4、SQL基線---為補充SQL概要並最終替代儲存提綱,11G中引入了SQL基線(靈活性與穩定性的結合)
只有在新的計劃被證實好於任何已存在的計劃時,它才允許計劃改變。
4、1 建立基線
DECLARE
V_SQL_ID v$sql.sql_id%type;
V_PLAN_COUNT NUMBER;
BEGIN
SELECT SQL_ID INTO V_SQL_ID FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT /*GHBASELINES1*/%';
V_PLAN_COUNT := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(SQL_ID => V_SQL_ID);
DBMS_OUTPUT.PUT_LINE(V_PLAN_COUNT||' PLANS LOADED');
END;
表dba_sql_plan_baselines可查基線狀態,ACCEPTED列為YES表示這個基線被啟用。
查基線對應的計劃
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(:V_SQL_HANDEL,NULL,'BASIC'));
進化基線
當發現新的執行計劃開銷低時,優化器就會建立新的基線。然而新的基線在經過核實之前不會被接受。
BEGIN
:V_REPORT := dbms_spm.evolve_sql_plan_baseline
(sql_handle=>:v_sql_handle,
verify=>'YES',--只有當未接受的計劃可帶來顯著提升,才會被接受,如果設定為NO,則所有未接受的計劃都會被接受。
commit => 'YES');--控制實際真正接受,或僅僅報告計劃是否符合標準
END;
自動化和配置基線
基線的使用主要由兩個資料庫引數控制
OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES 這個引數控制基線的自動收集,預設設定為FALSE,當將基設為TRUE時,基線會在SQL第一次執行時被自動建立。這樣,就沒必要再使用DBMS_SPM包來手工建立基線了。
OPTIMIZER_USE_SQL_PLAN_BASELINES 控制優化器對SQL基線的使用,預設值為TRUE,當為FALSE時,在優化器決定執行計劃時,就不會考慮基線。
固化基線
只需在前面的過程中做個小的修改:
...
v_plan-count := dbms_spm.load_plans_from_cursor_cache(sql_id=>v_sql_id,fixed=>'YES');
...
當有固化的基線存在時,即使有計劃發生變化,優化器也不會為這個SQL語句增加新的基線,一定是優化使用固化的基線。