一、并行机制的简述
并行处理的机制实际上就是把一个要扫描的数据集分成很多小数据集,Oracle会根据初始化参数 PARALLEL_MIN_SERVERS=n的值启动几个并行服务进程同时处理这些小数据集,最后将这些结果汇总,作为最终的处理结果返回给用户。
二、并行使用场景
1、Parallel query(并行查询)
执行并行查询是需要符合以下条件:
A、sql语句中有Hint提示,比如Parallel或者 Parallel_index。
C、多表关联中,至少有一个表执行全表扫描(Fulltable scan)或者跨分区的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;
下面从以上三个场景各举一例来说一下并行易踩的坑。
三、并行对执行计划的影响
某日,开发突然找过来:喂、DBA吗?有个测试环境的sql执行计划和生产环境不一样,严重影响测试进度。记得当时差不多是这样的,对方向我扔了一条执行计划有问题的sql,然后不说话。作为一个菜鸟,赶紧把生产执行计划和测试环境对比了一下,发现果真不一样,折腾了好久,才发现该sql中的某个表并行度为8,导致了执行计划异常。记得该表是TB级的大小,是个多表管理的查询语句,并行度为8之后走了全表扫描(Full table scan),可以想象是又多慢。因为是测试环境,谁做什么操作之后没有关闭并行就不深究了。下面看一下oracle联机文档:http://download.oracle.com/docs/cd/E11882_01/server.112/e10821/ex_plan.htm#PFGRF94687对并行处理的执行计划的解读。
sql>createtableemp2asselect*fromscott.emp; sql>altertableemp2parallel2;--可以查看dba_tables表degree列 sql>explainplanforselectsum(sal)fromemp2groupbydeptno; sql>select*fromtable(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Planhashvalue:3939201228 ------------------------------------------------------------------------------------------------------------------ |Id|Operation|Name|Rows|Bytes|Cost(%cpu)|Time|TQ|IN-OUT|PQDistrib| ------------------------------------------------------------------------------------------------------------------ |0|SELECTSTATEMENT||1|26|2(0)|00:00:01|||| |1|PXCOORDINATOR||||||||| |2|PXSENDQC(RANDOM)|:TQ10001|1|26|2(0)|00:00:01|Q1,01|P->S|QC(RAND)| |3|HASHGROUPBY||1|26|2(0)|00:00:01|Q1,01|PCWP|| |4|PXRECEIVE||1|26|2(0)|00:00:01|Q1,01|PCWP|| |5|PXSENDHASH|:TQ10000|1|26|2(0)|00:00:01|Q1,00|P->P|HASH| |6|HASHGROUPBY||1|26|2(0)|00:00:01|Q1,00|PCWP|| |7|PXBLOCKITERATOR||1|26|2(0)|00:00:01|Q1,00|PCWC|| |8|TABLEACCESSFULL|EMP2|1|26|2(0)|00:00:01|Q1,00|PCWP|| ------------------------------------------------------------------------------------------------------------------ Note ----- -dynamicsamplingusedforthisstatement(level=2) 19rowsselected.
当使用了并行执行,sql的执行计划中就会多出一列:in-out。该列帮助我们理解数据流的执行方法。它的一些值的含义如下:
Parallel to Serial(P->S): 表示一个并行操作发送数据给一个串行操作,通常是并行incheng将数据发送给并行调度进程。
Parallel to Parallel(P->P):表示一个并行操作向另一个并行操作发送数据,疆场是两个从属进程之间的数据交流。
Parallel Combined with parent(PCWP): 同一个从属进程执行的并行操作,同时父操作也是并行的。
Parallel Combined with Child(PCWC): 同一个从属进程执行的并行操作,子操作也是并行的。
Serial to Parallel(S->P): 一个串行操作发送数据给并行操作,如果select 部分是串行操作,就会出现这个情况。
如果知道了这些含义,再去解析执行计划的执行步骤就很容易了。这里强调一下,在处理某些操作之后,对表或者索引等对象开启了并行的,一定要记得关闭,不然后果很严重。
四、并行建主键唯一性索引的影响
又是某日,开发欲在测试环境对某一大表建主键唯一性索引(前期未规划好),语句执行了很长时间,因为其它人还需调用该表,但长时间的锁表,造成了不可用,于是请求DBA帮助,我看了语句之后,给出建议建索引时加上并行并以nologing的方式,然后让开发自己再去执行,可不久后,开发又找过来说还是很慢,查看没有任何阻塞之后,决定好好看看是不是真的很慢。经过一番折腾,终于知道慢的原因了,建主键约束时不会用到并行。解决方案分两步走,先建唯一性约束,再加主键约束。如下:
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); --主键建立并行是没有效果的
相关测试这里就不演示了,测试方法很简单,在建索引的过程中查询dba_tables表degree列就行了。这里需要强调的一点是对于表的设计规划,前期一定要做好。
五、并行DML无法生效
sql>explainplanforinsert/*+parallel(a,4)*/intoemp2aselect*fromemp; Explained. sql>select*fromtable(dbms_xplan.display()); PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------------------- Planhashvalue:3956160932 --------------------------------------------------------------------------------- |Id|Operation|Name|Rows|Bytes|Cost(%cpu)|Time| --------------------------------------------------------------------------------- |0|INSERTSTATEMENT||1|87|2(0)|00:00:01| |1|LOADTABLECONVENTIONAL|EMP2||||| |2|TABLEACCESSFULL|EMP|1|87|2(0)|00:00:01| --------------------------------------------------------------------------------- Note ----- -dynamicsamplingusedforthisstatement(level=2) 13rowsselected.
可以看到该DML语句在有HINT提示的情况下没有使用并行,那要怎样才能使它使用并行呢?很简单,只需要执行alter session enable parallel dml; 这里也可以想一下和之前的并行查询和并行DDL是不同的。
sql>altersessionenableparalleldml; Sessionaltered. sql>explainplanforinsert/*+parallel(a,4)*/intoemp2aselect*fromemp; Explained. sql>select*fromtable(dbms_xplan.display()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Planhashvalue:883381916 ----------------------------------------------------------------------------------------------------------------- |Id|Operation|Name|Rows|Bytes|Cost(%cpu)|Time|TQ|IN-OUT|PQDistrib| ----------------------------------------------------------------------------------------------------------------- |0|INSERTSTATEMENT||1|87|2(0)|00:00:01|||| |1|PXCOORDINATOR||||||||| |2|PXSENDQC(RANDOM)|:TQ10001|1|87|2(0)|00:00:01|Q1,01|P->S|QC(RAND)| |3|LOADASSELECT|EMP2|||||Q1,01|PCWP|| |4|PXRECEIVE||1|87|2(0)|00:00:01|Q1,01|PCWP|| |5|PXSENDROUND-ROBIN|:TQ10000|1|87|2(0)|00:00:01||S->P|RND-ROBIN| |6|TABLEACCESSFULL|EMP|1|87|2(0)|00:00:01|||| ----------------------------------------------------------------------------------------------------------------- Note ----- -dynamicsamplingusedforthisstatement(level=2) 17rowsselected.
执行之后很见效,从执行计划重可以很清楚的看到该DML语句利用了并行度。这里使用的的hint的方式提示语句使用并行,若表本身设置了并行度呢?这种情况也是一样的,需要香执行alter session enable parallel dml; DML语句才可以使用到并行。
还有一个情况需要注意的是,对于开启并行度之后的表存在事务未提交的,后续的事务一定会失败,报如下错误:ORA-12838: cannot read/modify an object after modifying it inparallel。
sql>altertableemp2parallel2; Tablealtered. sql>altersessionenableparalleldml; Sessionaltered. sql>insertintoemp2aselect*fromemp; 0rowscreated. sql>insertintoemp2aselect*fromemp; insertintoemp2aselect*fromemp * ERRORatline1: ORA-12838:cannotread/modifyanobjectaftermodifyingitinparallel
该问题在写存储过程的时候一定要注意,事务及时提交,但这里又涉及到一个性能问题了,所以对于表这些对象的并行度尽量不要开启。
总结:并行确实能带来性能上的提升,效率的提高等,但是凡事都有两面性,滥用并行的话会导致程序争议用,资源过度的消耗,并行是会产生排序的,所以了解清除并行的本质,闲时使用并行,合理规划。