在歷史數據轉出測試過程當中,經過不斷的優化,包括SQL調整和數據庫調整,從AWR中看到,基本上難以進行更多的性能提高,因而準備試試並行執行的特性,從這個任務的特色來分析,也比較適合採用這項技術。本文介紹了使用並行執行過程當中的經常使用SQL,以及遇到的一些問題,以及性能對比試驗的結果,而且分享了一些問題的解決經驗,分析了適合並行執行的場景。數據庫
並行執行經過充分利用硬件資源來實現特定任務的性能提高,將一個SQL語句同時分佈到多個CPU上去執行,從而縮短總的耗時。性能優化
Oracle的並行執行包括:服務器
1) 並行查詢session
2) 並行DML(insert,delete,update)app
3) 並行DDL(表和索引的建立)。性能
爲了方便參考使用,下面將收集的經常使用語句按並行執行的三個級別進行介紹:測試
l 對象級優化
設置表和索引的並行度,從而使用涉及這些對象的SQL操做按設定的並行度執行。ui
例如:alter table 門診費用記錄 parallel 8;日誌
alter index 門診費用記錄_IX_登記時間 parallel;
若是不指定並行度的值,Oracle會根據參數和CPU數來估算一個缺省值。
禁用並行度(指定並行度爲1或使用noparallel):
alter table 門診費用記錄 parallel 1;
alter index 門診費用記錄_IX_登記時間 noparallel;
若是不改變對象的並行度屬性,惟一能夠禁用並行查詢的方法是將初始化參數parallel_max_servers設置爲0。
l 會話級
人工啓用和禁用的語法以下:
ALTER Session ENABLE PARALLEL query[|DML|DDL];
ALTER Session DISABLE PARALLEL query[|DML|DDL];
強制按指定的並行度執行。
ALTER Session FORCE PARALLEL QUERY PARALLEL 8;
ALTER Session FORCE PARALLEL DML PARALLEL 8;
ALTER Session FORCE PARALLEL DDL PARALLEL 8;
強制並行對於遞歸SQL不起做用,但覆蓋表或索引上定義的並行度。
查詢當前會話是否啓用了並行執行:
(Oracle 10.2.0.1上,缺省啓用了並行QUERY和DDL,沒有啓用DML)
SQL> SELECT pq_status ,pdml_status, pddl_status
FROM v$session WHERE sid=sys_context('userenv','sid');
PQ_STATUS PDML_STATUS PDDL_STATUS
--------- ----------- -----------
ENABLED DISABLED ENABLED
l 語句級
經過在SQL中添加提示來指定並行執行及並行度。
優化器只是按指定的提示來考慮是否使用並行執行,並不會強制使用(它會選擇成本最低的那一個執行計劃)
例如:
Select /*+ parallel(t1,8)*/count(*) from 門診費用記錄 t1;
Create table 醫囑執行時間 parallel 8 as
select /*+ parallel(t1,8)*/* from醫囑執行時間 t1;
alter index 門診費用記錄_IX_登記時間 rebuild parallel 8;
注意:
並行DML須要先在會話級顯示的啓用,而且須要同時啓用並行查詢;
例:
SQL>ALTER Session ENABLE PARALLEL DML;
SQL> ALTER Session ENABLE PARALLEL QUERY;
SQL> Update /*+ parallel(t1,8)*/ 門診費用記錄 t1
Set 待轉出 = 132
Where 結賬id In
(Select /*+ parallel(t2,8)*/結賬id From 病人預交記錄 t2 Where 待轉出 = 132);
若是不提交事務,該會話的後續SQL沒法訪問被修改的表,查詢未提交事務的表,將會返回錯誤:」ora-12838:沒法讀取、修改一個被並行修改過的表」
定義主鍵約束時,沒法並行的自動建立主鍵索引,但能夠採起如下變通方式:
CREATE UNIQUE INDEX 檢驗標本記錄_UQ_標本序號
ON 檢驗標本記錄(覈收時間, 儀器ID, 標本序號, 標本類別) PARALLEL 8;
ALTER TABLE 檢驗標本記錄 ADD CONSTRAINT
檢驗標本記錄_UQ_標本序號 Unique (覈收時間, 儀器ID, 標本序號, 標本類別);
這種方式建立的主鍵約束與自動建立的有一個差異,就是刪除主鍵的時候,不會自動刪除對應的索引,須要增長刪除索引的語法,例:
ALTER TABLE 檢驗標本記錄 drop
CONSTRAINT 檢驗標本記錄_UQ_標本序號 cascade drop index;
另外,關於並行查詢的參數配置,大部分狀況下,無須調整,網上的資料比較多,這裏再也不一一列舉。僅說明一個參數:
當執行並行重建索引時,可能會遇到ora-00600錯誤,經過修改參數parallel_execution_message_size可解決這個問題,例:
SQL> alter system set parallel_execution_message_size=8192 scope=spfile;
缺省值爲2148,對於通常的並行任務,這個值過小。
修改後需重啓數據庫。
l 並行查詢及並行DML
因爲所使用的歷史數據轉出,大部分查詢均是索引範圍掃描,沒有全表掃描,因此,不適合並行執行。
可是,因爲一次意外操做:索引壓縮重建(並行DDL),執行後致使索引的屬性自動加上了並行度,致使相關的SQL查詢自動啓用了並行查詢,結果,執行計劃採用了大表全表掃描,採用hash鏈接或嵌套鏈接,致使查詢異常緩慢。
一些複雜的SQL執行超過了一個小時,甚至下面這種簡單的SQL執行超過了5個小時仍然沒有返回結果:
Update /*+ rule*/ 病人醫囑計價
Set 待轉出 = n_批次
Where 醫囑id In (Select ID From 病人醫囑記錄 Where 待轉出 = n_批次);
查看執行計劃,發現採用了全表掃描+嵌套鏈接索引的方式。
而且,提示字rule失效,優化器模式變成了CBO。最後,取消了索引的並行度,而後,重建索引,禁用了壓縮特性,最終執行計劃才恢復了正常。
由於普通的索引範圍掃描並不能使用並行查詢(除非是分區索引),因此,優化器會選擇全表掃描方式,可是不少時候這並非咱們所指望的訪問方式。
因此,並行查詢和並行DML必定要慎重,不然,性能差異很是大。
l 直接路徑插入
爲了快速的加載大量數據,採用直接路徑插入方式能夠大幅提高插入性能。
直接路徑插入自動對insert 和Select操做採用了並行執行,而且目標表採用nologging最小日誌模式的話,試驗代表,最高可減小5倍的耗時。
例:
Insert Into /*+ append*/H住院費用記錄(ID, 記錄性質, NO, ……)
Select ID, 記錄性質, NO, …… From 住院費用記錄 Where 待轉出 = 132;
l 並行DDL
歷史數據轉出過程當中,須要重建轉出表上的查詢所用到的索引,以便及時回收空間,加快查詢速度,但這個索引重建的過程很是耗時。測試環境的配置爲:32G內存、32路CPU(4*8)、Raid10的SCSI硬盤。
測試結果代表:
沒有並行時,重建索引須要36分鐘,並行執行只須要16分鐘。
由於磁盤IO所限,該環境下並行度爲8時最快
l 並行收集統計信息
收集對象統計信息的時候,有一個參數能夠指定並行度,並行的效果很是明顯。試驗代表,收集ZLHIS的全部對象,並行執行能夠將整個時間由1個半小時縮短到30分鐘左右。
並行執行屬於Oracle的OLAP應用特性之一,若是你有一些耗時很長的任務,而且服務器有大量的閒置資源(CPU,內存,IO帶寬),則比較適合採用並行執行技術,它能夠給你帶來成倍的性能提高效果,不然,並行執行可能會因爲大量的消耗資源從而影響其餘人的正常使用。因此,並行執行通常狀況,較少的在OLTP場合中應用,由於一般咱們並不但願某一我的佔用過多的系統資源。
1) Oracle 性能診斷藝術.Christian Antognini.2009
2) Oracle 性能優化求生指南.Guy Harrison .2012
--無並行
22:26:19 SQL> exec Zl1_Datamove_Reb(100, 1, 6);
PL/SQL procedure successfully completed
Executed in 2199.734 seconds
--------------------------------------------------------------
SQL> ALTER session FORCE PARALLEL DDL PARALLEL 24;
SQL> exec Zl1_Datamove_Reb(100, 1, 6);
PL/SQL procedure successfully completed
Executed in 1450.828 seconds
--------------------------------------------------------------
SQL> ALTER session FORCE PARALLEL DDL PARALLEL 16;
SQL> exec Zl1_Datamove_Reb(100, 1, 6);
PL/SQL procedure successfully completed
Executed in 1272.063 seconds
--------------------------------------------------------------
SQL> ALTER session FORCE PARALLEL DDL PARALLEL 8;
SQL> exec Zl1_Datamove_Reb(100, 1, 6);
PL/SQL procedure successfully completed
Executed in 1018.765 seconds
--------------------------------------------------------------
SQL> ALTER session FORCE PARALLEL DDL PARALLEL 4;
SQL> exec Zl1_Datamove_Reb(100, 1, 6);
PL/SQL procedure successfully completed
Executed in 1125.719 seconds