Oracle使用并行踩過(guò)的坑
【引自朱wei的博客】一、并行機(jī)制的簡(jiǎn)述
并行處理的機(jī)制實(shí)際上就是把一個(gè)要掃描的數(shù)據(jù)集分成很多小數(shù)據(jù)集,Oracle會(huì)根據(jù)初始化參數(shù) PARALLEL_MIN_SERVERS=n的值啟動(dòng)幾個(gè)并行服務(wù)進(jìn)程同時(shí)處理這些小數(shù)據(jù)集,***將這些結(jié)果匯總,作為最終的處理結(jié)果返回給用戶。
二、并行使用場(chǎng)景
1、Parallel query(并行查詢)
執(zhí)行并行查詢是需要符合以下條件:
A、SQL語(yǔ)句中有Hint提示,比如Parallel或者 Parallel_index。
B、SQL語(yǔ)句中引用的對(duì)象被設(shè)置了并行屬性。
C、多表關(guān)聯(lián)中,至少有一個(gè)表執(zhí)行全表掃描(Fulltable scan)或者跨分區(qū)的Index range SCAN。
2、Parallel DDL(并行DDL操作,如建表,建索引等)
如:createtable xx parallel 4 as select * from xxx;
create index xxx on tab_xx(column) parallel 4;
3、Parallel DML(并行DML操作,如insert、update、delete等)
如:insert/*+parallel(t 2) */ into t select /*+parallel(t1 2) */ * from t1;
下面從以上三個(gè)場(chǎng)景各舉一例來(lái)說(shuō)一下并行易踩的坑。
三、并行對(duì)執(zhí)行計(jì)劃的影響
某日,開發(fā)突然找過(guò)來(lái):喂、DBA嗎?有個(gè)測(cè)試環(huán)境的SQL執(zhí)行計(jì)劃和生產(chǎn)環(huán)境不一樣,嚴(yán)重影響測(cè)試進(jìn)度。記得當(dāng)時(shí)差不多是這樣的,對(duì)方向我扔了一條執(zhí)行計(jì)劃有問(wèn)題的SQL,然后不說(shuō)話。作為一個(gè)菜鳥,趕緊把生產(chǎn)執(zhí)行計(jì)劃和測(cè)試環(huán)境對(duì)比了一下,發(fā)現(xiàn)果真不一樣,折騰了好久,才發(fā)現(xiàn)該SQL中的某個(gè)表并行度為8,導(dǎo)致了執(zhí)行計(jì)劃異常。記得該表是TB級(jí)的大小,是個(gè)多表管理的查詢語(yǔ)句,并行度為8之后走了全表掃描(Full table scan),可以想象是又多慢。因?yàn)槭菧y(cè)試環(huán)境,誰(shuí)做什么操作之后沒有關(guān)閉并行就不深究了。下面看一下oracle聯(lián)機(jī)文檔:http://download.oracle.com/docs/cd/E11882_01/server.112/e10821/ex_plan.htm#PFGRF94687對(duì)并行處理的執(zhí)行計(jì)劃的解讀。
- SQL>createtable emp2 as select * from scott.emp;
- SQL>altertable emp2 parallel 2; --可以查看dba_tables表degree列
- SQL>explainplan for select sum(sal) from emp2 group by deptno;
- SQL> select * fromtable(dbms_xplan.display());
- PLAN_TABLE_OUTPUT
- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Plan hash value: 3939201228
- ------------------------------------------------------------------------------------------------------------------
- | Id | Operation |Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
- ------------------------------------------------------------------------------------------------------------------
- | 0| SELECT STATEMENT | | 1| 26 | 2 (0)| 00:00:01 | | | |
- | 1| PX COORDINATOR | | | | | | | | |
- | 2| PX SEND QC (RANDOM) | :TQ10001 | 1 | 26 | 2 (0)| 00:00:01 | Q1,01 | P->S |QC (RAND) |
- | 3| HASH GROUP BY | | 1 | 26 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
- | 4| PX RECEIVE | | 1 | 26 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
- | 5| PX SEND HASH | :TQ10000 | 1 | 26 | 2 (0)| 00:00:01 | Q1,00 | P->P |HASH |
- | 6| HASH GROUP BY | | 1 | 26 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
- | 7| PX BLOCK ITERATOR | | 1 | 26 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
- | 8| TABLE ACCESS FULL| EMP2 | 1 | 26 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
- ------------------------------------------------------------------------------------------------------------------
- Note
- -----
- -dynamic sampling used for this statement (level=2)
- 19 rows selected.
當(dāng)使用了并行執(zhí)行,SQL的執(zhí)行計(jì)劃中就會(huì)多出一列:in-out。該列幫助我們理解數(shù)據(jù)流的執(zhí)行方法。它的一些值的含義如下:
Parallel to Serial(P->S): 表示一個(gè)并行操作發(fā)送數(shù)據(jù)給一個(gè)串行操作,通常是并行incheng將數(shù)據(jù)發(fā)送給并行調(diào)度進(jìn)程。
Parallel to Parallel(P->P):表示一個(gè)并行操作向另一個(gè)并行操作發(fā)送數(shù)據(jù),疆場(chǎng)是兩個(gè)從屬進(jìn)程之間的數(shù)據(jù)交流。
Parallel Combined with parent(PCWP): 同一個(gè)從屬進(jìn)程執(zhí)行的并行操作,同時(shí)父操作也是并行的。
Parallel Combined with Child(PCWC): 同一個(gè)從屬進(jìn)程執(zhí)行的并行操作,子操作也是并行的。
Serial to Parallel(S->P): 一個(gè)串行操作發(fā)送數(shù)據(jù)給并行操作,如果select 部分是串行操作,就會(huì)出現(xiàn)這個(gè)情況。
如果知道了這些含義,再去解析執(zhí)行計(jì)劃的執(zhí)行步驟就很容易了。這里強(qiáng)調(diào)一下,在處理某些操作之后,對(duì)表或者索引等對(duì)象開啟了并行的,一定要記得關(guān)閉,不然后果很嚴(yán)重。
四、并行建主鍵唯一性索引的影響
又是某日,開發(fā)欲在測(cè)試環(huán)境對(duì)某一大表建主鍵唯一性索引(前期未規(guī)劃好),語(yǔ)句執(zhí)行了很長(zhǎng)時(shí)間,因?yàn)槠渌诉€需調(diào)用該表,但長(zhǎng)時(shí)間的鎖表,造成了不可用,于是請(qǐng)求DBA幫助,我看了語(yǔ)句之后,給出建議建索引時(shí)加上并行并以nologing的方式,然后讓開發(fā)自己再去執(zhí)行,可不久后,開發(fā)又找過(guò)來(lái)說(shuō)還是很慢,查看沒有任何阻塞之后,決定好好看看是不是真的很慢。經(jīng)過(guò)一番折騰,終于知道慢的原因了,建主鍵約束時(shí)不會(huì)用到并行。解決方案分兩步走,先建唯一性約束,再加主鍵約束。如下:
1、開并行重建唯一索引:
create unique index schema.xxx onschema.table_name(column1,column2) parallel 16;
2、取消并行:alter indexschema.xxx noparallel; --索引建完后,一定記得取消并行
3、建主鍵約束:alter tableschame.xxx add constraint xxx primary key(column1,column2); --主鍵建立并行是沒有效果的
相關(guān)測(cè)試這里就不演示了,測(cè)試方法很簡(jiǎn)單,在建索引的過(guò)程中查詢dba_tables表degree列就行了。這里需要強(qiáng)調(diào)的一點(diǎn)是對(duì)于表的設(shè)計(jì)規(guī)劃,前期一定要做好。
五、并行DML無(wú)法生效
- SQL> explain plan for insert/*+parallel(a,4) */ into emp2 a select * from emp;
- Explained.
- SQL> select * fromtable(dbms_xplan.display());
- PLAN_TABLE_OUTPUT
- -----------------------------------------------------------------------------------------
- Plan hash value: 3956160932
- ---------------------------------------------------------------------------------
- | Id | Operation | Name |Rows | Bytes | Cost (%CPU)| Time |
- ---------------------------------------------------------------------------------
- | 0| INSERT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
- | 1| LOAD TABLE CONVENTIONAL | EMP2 || | | |
- | 2| TABLE ACCESS FULL | EMP | 1 | 87 | 2 (0)| 00:00:01 |
- ---------------------------------------------------------------------------------
- Note
- -----
- -dynamic sampling used for this statement (level=2)
- 13 rows selected.
可以看到該DML語(yǔ)句在有HINT提示的情況下沒有使用并行,那要怎樣才能使它使用并行呢?很簡(jiǎn)單,只需要執(zhí)行alter session enable parallel dml; 這里也可以想一下和之前的并行查詢和并行DDL是不同的。
- SQL> alter session enable parallel dml;
- Session altered.
- SQL> explain plan for insert/*+parallel(a,4) */ into emp2 a select * from emp;
- Explained.
- SQL> select * fromtable(dbms_xplan.display());
- PLAN_TABLE_OUTPUT
- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- Plan hash value: 883381916
- -----------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name |Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
- -----------------------------------------------------------------------------------------------------------------
- | 0| INSERT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 | | | |
- | 1| PX COORDINATOR | | | | | | | | |
- | 2| PX SEND QC (RANDOM) | :TQ10001 | 1 | 87 | 2 (0)| 00:00:01 | Q1,01 | P->S |QC (RAND)|
- | 3| LOAD AS SELECT| EMP2 | | | | | Q1,01 | PCWP | |
- | 4| PX RECEIVE | | 1 | 87 | 2 (0)| 00:00:01 | Q1,01 | PCWP | |
- | 5| PX SEND ROUND-ROBIN| :TQ10000 | 1 | 87| 2 (0)| 00:00:01 | | S->P | RND-ROBIN |
- | 6| TABLE ACCESS FULL | EMP | 1 | 87| 2 (0)| 00:00:01 | | | |
- -----------------------------------------------------------------------------------------------------------------
- Note
- -----
- -dynamic sampling used for this statement (level=2)
- 17 rows selected.
執(zhí)行之后很見效,從執(zhí)行計(jì)劃重可以很清楚的看到該DML語(yǔ)句利用了并行度。這里使用的的hint的方式提示語(yǔ)句使用并行,若表本身設(shè)置了并行度呢?這種情況也是一樣的,需要香執(zhí)行alter session enable parallel dml; DML語(yǔ)句才可以使用到并行。
還有一個(gè)情況需要注意的是,對(duì)于開啟并行度之后的表存在事務(wù)未提交的,后續(xù)的事務(wù)一定會(huì)失敗,報(bào)如下錯(cuò)誤:ORA-12838: cannot read/modify an object after modifying it inparallel。
- SQL> alter table emp2 parallel 2;
- Table altered.
- SQL> alter session enable parallel dml;
- Session altered.
- SQL> insert into emp2 a select * fromemp;
- 0 rows created.
- SQL> insert into emp2 a select * fromemp;
- insert into emp2 a select * from emp
- *
- ERROR at line 1:
- ORA-12838: cannot read/modify an objectafter modifying it in parallel
該問(wèn)題在寫存儲(chǔ)過(guò)程的時(shí)候一定要注意,事務(wù)及時(shí)提交,但這里又涉及到一個(gè)性能問(wèn)題了,所以對(duì)于表這些對(duì)象的并行度盡量不要開啟。
總結(jié):并行確實(shí)能帶來(lái)性能上的提升,效率的提高等,但是凡事都有兩面性,濫用并行的話會(huì)導(dǎo)致程序爭(zhēng)議用,資源過(guò)度的消耗,并行是會(huì)產(chǎn)生排序的,所以了解清除并行的本質(zhì),閑時(shí)使用并行,合理規(guī)劃。