2014-09-25 Created By BaoXinjian
一、摘要
對於一個大的任務,一般的做法是利用一個進程,串行的執行,如果系統資源足夠,可以采用parallel技術,把一個大的任務分成若干個小的任務,同時啟用n個進程/線程,並行的處理這些小的任務,這些並發的進程稱為並行執行服務器(parallel executeion server),這些並發進程由一個稱為並發協調進程的進程來管理。
1. 啟用Parallel前的忠告:
只有在需要處理一個很大的任務,如需要幾十分鍾,幾個小時的作業中,並且要有足夠的系統資源的情況下(這些資源包括cpu,內存,io),您才應該考慮使用parallel。
否則,在一個多並發用戶下,系統本身資源負擔已經很大的情況下,
啟用parallel,將會導致某一個會話試圖占用了所有的資源,其他會話不得不去等待,從而導致系統系能反而下降的情況,
一般情況下,oltp系統不要使用parallel,oltp系統中可以考慮去使用。
Oracle的並發技術可以將一個大任務分解為多個小任務由多個進程共同完成。合理地使用並發可以充分利用系統資源,提高效率。
2. Parallel分類
並行查詢:parallel query
並行DML: parallel dml pdml
並行DDL: parallel ddl pddl
3. 適用場合
3.1 適用parallel的兩個條件
(1). 大的任務,如全表掃描大表這和日常生活中的經驗是一樣的,小任務自己完成都比派發任務省事
(2).系統有足夠的資源(cpu/io)
3.2 換句話說,並發是在系統資源充足、用戶少的系統上,為了充分利用系統資源以提高任務處理速度而設計的一種技術。以下是幾種場景:
(1). OLTP系統 有大量用戶和session,如果每個session使用並發查詢將導致系統崩潰。但也有例外例如計費系統月底或下班后沒有或用戶很少訪問,運行批處理程序,此時可使用並發提高速度
(2). 數據倉庫系統 通常可使用並發查詢、PDML等並發,注意有些數據倉庫系統也提供給大量用戶訪問,這種系統有某些OLTP特性,應慎用並發
(3). 無論是OLTP還是數據倉庫,維護期間使用parallel ddl和PDML對管理員來說是非常有用的
二、並行查詢
並行查詢允許將一個sql select語句划分為多個較小的查詢,每個部分的查詢並發地運行,然后將各個部分的結果組合起來,提供最終的結果,
多用於全表掃描,索引全掃描等,大表的掃描和連接、創建大的索引、分區索引掃描、大批量插入更新和刪除
1. 啟用並行查詢
Setup1. 啟用並行查詢
SQL> ALTER TABLE T1 PARALLEL;
告知oracle,對T1啟用parallel查詢,但並行度要參照系統的資源負載狀況來確定。
Setup2. 利用hints提示,啟用並行,同時也可以告知明確的並行度,否則oracle自行決定啟用的並行度,這些提示只對該sql語句有效。
SQL> select /*+ parallel(t1 8) */ count(*) from t1;
Step1. 查詢並行度
SQL> select degree from user_tables where table_name='T1';
DEGREE = DEFAULT
Step2. 並行度為Default,其值由下面2個參數決定
SQL> show parameter cpu NAME TYPE VALUE cpu_count integer 2 parallel_threads_per_cpu integer 2
cpu_count表示cpu數
parallel_threads_per_cpu表示每個cpu允許的並行進程數
default情況下,並行數為cpu_count*parallel_threads_per_cpu
2. 取消並行查詢
SQL> alter table t1 noparallel;
SQL> select degree from user_tables where table_name='T1'; DEGREE 1
3. 數據字典視圖
select * from v$px_session
sid:各個並行會話的sid
qcsid:query coordinator sid,查詢協調器sid
三、並行DML
並行DML包括insert,update,delete,merge,在pdml期間,oracle可以使用多個並行執行服務器來執行insert,update,delete,merge,多個會話同時執行,同時每個會話(並發進程)都有自己的undo段,都是獨立的一個事務,這些事務要么由parallel dml協調器進程提交,要么都rollback。
1. 在一個有充足I/o帶寬的多cpu主機中,對於大規模的dml,速度可能會有很大的提升,尤其是在大型的數據倉庫環境中。
Steup1. 並行dml需要顯示的啟用
SQL> alter session enable parallel dml;
Setup2. Disable並行dml
SQL> alter session disable parallel dml;
2. 一個例子 Parallel DML
ALTER TABLE emp PARALLEL (10); ALTER SESSION ENABLE PARALLEL DML; INSERT INTO emp SELECT * FROM t_emp; COMMIT; ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ PARALLEL(emp,12) */ INTO emp SELECT /*+ PARALLEL(t_emp,12) */ * FROM t_emp; COMMIT;
注意:使用parallel后,insert select * 語句自動就使用direct-load了,此時不再需要使用append hint( /*+APPEND */)
3. Parallel DML的限制:
- 不支持有trigger的表,在上面做PDML,能成功,但忽略了並發性;
- 不支持某些約束,例如self-referential integrity。原因是PDML分為多個獨立的session去修改數據,無法保證某些完整性;容易引起死鎖已經其他鎖問題;
- 一個session使用了PDML,在commit/rollback之前,另一個session無法再使用PDML;
- Advanced replication不支持(因為使用了trigger);
- Deferred constraints(約束的deferred模式指修改操作在提交時才去驗證是否滿足約束條件)不支持;
- 分布式事務不支持;
- Clustered tables不支持;
- 當違反這些限制,PDML要么報錯,要么忽略並行度;
四、並行DDL
並行DDL提供了DBA使用全部機器資源的能力,常用的Parallel命令
- create table as select ……
- create index
- alter index rebuild
- alter table move
- alter table split
在這些sql語句后面加上parallel子句
例子1. Alter Table
SQL> alter table t1 move parallel; Table altered
例子2. Alter Index
SQL> create index T1_IDX on T1 (OWNER, OBJECT_TYPE) tablespace SYSTEM parallel;
五、並發與空間浪費
Parallel DDL以及某些PDML依賴於direct path load,即繞過databuffer直接寫數據文件。
例如,create table as select ,insert /*+APPEND */,
這會形成空間浪費
例如倒入1010M數據,每個extent 100m,direct path load會新分配100m 的extent來存放數據(如果有小於100m的extent,常規insert可以用這些空間)。
假設10個並發,每個並發倒入101M數據,會創建2個extent,則總共會創建20個extent,則形成990m空間浪費。
一方面浪費了空間(如果表創建之后有常規insert,則能使用這些空間),另一方面全表掃描時會搜索這些空的extent,這也降低了全表掃描的速度。
表空間的extent管理有兩種方式,
unform size,則每個extent大小相同,
autoallocate是oracle根據內部機制決定extent大小,
更靈活Uniform 方式不支持extent trimming,而autoallocate在parallel ddl中用到extent trimming,減少了空間浪費。
因此在頻繁使用parallel DDL操作的表空間上,要么減少uniform size每個extent的大小,要么使用autoallocate ,以減少空間浪費。
六、並發存儲過程開發
以下是一個常見任務:掃描全表,修改數據,再寫入新的表
如果一個進程處理太慢,我們通常會自己將數據划分,然后開多個進程調用。
使用11G R2 內置的並發包:DBMS_PARALLLEL_EXECUTE,大大簡化了這一過程(11G R2之前,沒有內置的並發程序包,需要手工按照rowid或主鍵划分大表,然后通過dbms_job或dbms_schedule並發調用。)
程序的目的是刪除bmf中orig_bill_ref_no like '18%'的記錄,本來一句sql可以完成,由於數據量太大,系統回滾段不足。因此開發人員准備分多個進程運行
DECLARE
CURSOR c1 IS
SELECT orig_bill_ref_no FROM bmf WHERE orig_bill_ref_no LIKE '18%' AND MOD (account_no, 5) = 0; BEGIN
FOR r1 IN c1 LOOP DELETE FROM bmf WHERE orig_bill_ref_no = r1.orig_bill_ref_no; COMMIT; END LOOP; COMMIT; END; /
這樣的寫法會有什么問題呢,很快就遇到snapshot too old錯誤了。原因是select打開bmf游標,同時修改bmf並commit數據,由於查詢一致性要求,打開的游標要看到的是bmf修改之前的情況,這是從undo去讀的,因此一旦時間超出undo_retention,undo信息過期,就報snapshot too old了。
使用Oracle並發包進行測試
Step1. 創建過程serial過程,用來被多個並發線程調用
/* Formatted on 2014/9/25 12:02:02 (QP5 v5.115.810.9015) */
CREATE OR REPLACE PROCEDURE serial (p_lo_rid IN ROWID, p_hi_rid IN ROWID) IS
BEGIN
DELETE FROM bmf WHERE ROWID BETWEEN p_lo_rid AND p_hi_rid AND orig_bill_ref_no LIKE '15%'; END; /
Step2. 按照rowid將表划分為多個chunk,供線程調用
BEGIN dbms_parallel_execute.create_task ('PROCESS BIG TABLE'); dbms_parallel_execute.create_chunks_by_rowid ( task_name => 'PROCESS BIG TABLE', table_owner => 'LUW', table_name => 'BMF', by_row => FALSE, --不按行記錄數而按block數
chunk_size => 2000 ); END; /
SELECT *
FROM ( SELECT chunk_id, status, start_rowid, end_rowid FROM dba_parallel_execute_chunks WHERE task_name = 'PROCESS BIG TABLE'
ORDER BY chunk_id) WHERE ROWNUM <= 5
/
Step3. 發起並發任務,按照第2步對表的划分來分配並運行任務
BEGIN dbms_parallel_execute.run_task ( task_name => 'PROCESS BIG TABLE', sql_stmt => 'begin serial( :start_id, :end_id ); end;', language_flag => DBMS_SQL.NATIVE, parallel_level => 4 ); END; /
Step4. 刪除並發作業
BEGIN dbms_parallel_execute.drop_task ('process big table'); END; /
Step5 性能比較
那么使用並發和簡單的delete相比,速度怎樣呢
1. 使用並發:
PL/SQL procedure successfully completed.
Elapsed: 00:00:03.07
2. 直接delete:
delete from bmf where orig_bill_ref_no like '15%';
403525 rows deleted.
Elapsed: 00:00:08.12
3. 這說明使用並發提高了速度,更別說對回滾段的空間要求也少了。
Thanks and Regards
參考: http://blog.itpub.net/18474/viewspace-1060729/