天天看點

oracle資料庫優化一則

本次優化涉及到oracle資料庫大量insert 資料索引帶來的開銷,使用append、parallel的方式進行改善性能。

<b>一、首先熟悉一下oracle hint的方法</b>

oracle hints是一種機制,用來告訴優化器按照我們的告訴它的方式生成執行計劃。我們可以用oracle hints來實作:

1) 使用的優化器的類型

2) 基于代價的優化器的優化目标,是all_rows還是first_rows。

3) 表的通路路徑,是全表掃描,還是索引掃描,還是直接利用rowid。

4) 表之間的連接配接類型

5) 表之間的連接配接順序

6) 語句的并行程度

本次案例會用到2個hint,append 和parallel,環境是一個資料倉庫場景,業務資料處理具有單一性,非常适合通過并行提高單次大業務的速度。

<b>二、append方式加載資料</b>

/*+ append */以直接加載的方式将資料加載入庫,它是從hwm的位置開始插入,可能會造成空間浪費的。非歸檔模式下可以減少redo的産生;歸檔模式下,一般情況下資料庫會強制logging,歸檔減少不了。

insert into t /*+ append */ select * from t;

<b>三、再來說一下oracle的并行</b>

對于oltp類型的資料庫,除非隻用于做統計、報表類的表或索引,建議不對相關表或索引調置并行度。在資料庫有開啟并行查詢的情況下,在表或索引上存在預設并行度,将導緻資料庫優先采用全表或全索引掃描的執行計劃,另外将生成多個并行子程序,對于oltp類應用将反而降低相關sql的執行效率。

   oracle在并行處理時,會啟動多少個并行程序來同時執行任務,并行度越高, 并行程序越多,執行速度 會越快,預設是noparallel,如果我們設定并行度為default值,那麼此時的并行度是:

伺服器cpu數*每個cpu啟用的線程數(parallel_threads_per_cpu),oltp環境 是以一般建議使用noparallel,或者将并行度設定為1,而不是default。

并行度hint的使用方法:

/*+ parallel(table_name n) */ 

在sql中指定執行的并行度,這個值将會覆寫自身的并行度

select /*+ parallel(t 4) */ count(*)  from t;

/*+ no_parallel(table_name) */ 

在sql中指定執行的不使用并行

select /*+ no_parallel(t) */ count(*)  from t;

<b>四、索引和insert的關系</b>

oracle在insert資料的過程中,會同時更新索引,索引過多對insert非常不利,索引要按需建立,加載資料時雖然推薦禁用索引,但一般表上會同時存在查詢操作,是以索引也必須存在。

<b>五、在優化客戶系統前,先做一個測試。</b>

1、準備表和資料

testtb 表從dba_objects中取數86381 條資料,testtb 将作為資料加載到testtb1的資料來源,testtb 上面沒有索引,在業務上使用insert into select 計算資料時,select段要首先控制其性能,這裡測試咱不涉及select段的性能。

sql&gt; create table testtb as select * from dba_objects where 1=0;

sql&gt; create table testtb1 as select * from dba_objects where 1=0;

sql&gt; insert into testtb1 select * from testtb;

345524 rows created.

elapsed: 00:00:01.49

我們看到插入資料&lt;2s鐘,此時增加一個索引

create index ind_object_name_testtb on testtb1(object_name);

elapsed: 00:00:14.46 &lt;&lt;插入入資料将近15s

再增加索引

create index ind_object_id_testtb on testtb1(object_id);

elapsed: 00:00:20.00&lt;&lt;插入入資料将近20s

create index ind_created_testtb on testtb1(created);

create index ind_created_object_id_testtb on testtb1(created,object_id);

elapsed: 00:01:01.18&lt;&lt;插入入資料已經到60s以上

假如這些索引都是我們必須的,接下來該hint出場了

insert /*+append parallel(8)*/ into testtb1 select * from testtb;

sql&gt; insert /*+append parallel(8)*/ into testtb1 select * from testtb;

elapsed: 00:00:21.43&lt;&lt;插入入資料21s

我們來看看執行過程

insert into testtb1 select * from testtb;

oracle資料庫優化一則
oracle資料庫優化一則

加hint提示後,select段使用的并行,但是load as select并沒有使用并行,也就是說,parallel隻對select段起作用了。

我們再來看看alter session enable parallel dml;

oracle資料庫優化一則

此時加載資料也有并行,使用者是使用pakage 和存儲過程執行業務流,

create or replace procedure proc_1 authid current_user parallel_enable as

begin

insert /*+append parallel(2)*/ into testtb1 select * from testtb;

commit;

dbms_output.put_line('haved insert ok!');

end;

/

通過10046事件跟蹤存儲過程的執行

oradebug setmypid;

oradebug unlimit;

oradebug event 10046 trace name context forever, level 12;

exec proc_1;

oradebug event 10046 trace name context off;

oradebug tracefile_name;

經過測試,存儲過程中的insert段是無法使用會話級并行的。這一點将在12c得到優化,hint中增加了enable_parallel_dml提示,同時這個參數包含了append的特性。

oracle資料庫優化一則

2、真實的場景

oracle資料庫優化一則
oracle資料庫優化一則

insert 語句已經使用了append 和parallel提示進行了優化,但執行1972s還是不能接受,檢視插入的對象表,生産環境上該表的索引有8個,包含3個複合索引,測試環境雖然也有8個索引,但是插入速度比生産快,但兩者環境不同,不能按照具體數值比較,測試環境索引是優化後的,去掉了多列的複合索引,開發兄弟把生産的索引和測試環境比照進行了重建,當晚執行時間下降到了359s,是以索引一定要按需建立、優化建立。

oracle資料庫優化一則

這條sql執行273s,也是insert into ……select……的類型操作,select部分通過/*+ append parallel */提示從89s 縮減到8s。

六、總結

1. 建立必要的索引,廢棄的索引盡快清理

2. 建立不同資料的生命周期,按周期清理,曆史歸并等

3. 合理使用并行 /*+ parallel(8)*/

5. insert 表可通過/*+ append */提示提高插入速度,但要持續關注空間使用。