关于Oracle中的并行,可以说是一把双刃剑,用得好,可以充分利用系统资源,提升数据库的处理能力,用得不好,可能会适得其反。
并行的基本使用方法,对于大部分SQL开发者和DBA来说,并行的一些最基本的使用方法还没有完全掌握,为此老虎刘老师特意写了一篇文章《关于parallel(并行)的几个基本常识》,着重介绍一下并行使用的常见问题及注意事项,非常受益。
1、什么时候使用并行?
常见的场景有:
a) 普通SQL最常见的情况就是大表的全表扫描,还有就是大的索引的快速全扫描(注意,index fast full scan可以使用并行,index full scan 不能使用并行)。
需要纠正一个误区:SQL执行慢就可以通过使用并行或是增加并行来提高速度。
正解:并行能否发挥作用要看SQL的具体执行计划,比如标量子查询或是DB link,增大并行带来的性能提升是微乎其微的!
多大的表算大表?
至少要百万级以上记录的表吧。如果几亿甚至十几亿记录数的表全表扫描不使用并行,SQL的执行时间会相当长,特别是表在SQL执行的过程中如果还有其他session的DML操作的时候。
OLTP系统的正常事务一般不会使用大表全扫描的执行计划,如果有一些统计分析的业务,建议在系统资源相对空闲的时候开启并行。
b) 用create table As Select创建一张大表,如
create table test parallel 16 as select .... from t1,t2 where .....;
alter table test noparallel;
c) 创建或重建索引
create index idx_test on table_A(name) parallel 8;
alter index idx_test noparallel;
d) 大表收集统计信息,可以设置并行,如degree=>8
其他不常见的操作还有表压缩等,一些比较耗时的分区操作也可以查查语法,看看是否支持并行操作。
2、并行度的选择
一般使用2的幂作为并行度,如2、4、8、16等,正常情况并行度不要设置太高,建议最多不要超过32。当然,特殊情况特殊对待,强悍的系统(比如 exadata),如果需要非常高的响应速度,并行度再多个几倍也不是问题。并行高的时候并发就要减少,否则可能会耗光并行资源。
3、并行hint的写法
通常我们都会使用hint在SQL级别设置并行,一般不在表上和索引上设置并行度,所以我们上面并行创建表和索引的例子,后面都伴随着一个noparallel,如果在创建表或索引时使用了并行,要把它改成noparallel或parallel 1 :
alter table/index table_name/index_name noparallel/parallel 1;
Hint的写法在10g和11g+有很大差别,11g+就方便很多。
10g 及以下:
每个需要并行的表都要指定并行,如 /*+ parallel(a 4) parallel(b 4) */ ,如果SQL涉及的表较多,那么hint会比较长;如果内联视图较多,经常会出来遗漏的情况。如果某个表没有指定并行,那么就只能串行,如果某个大表忘 了写,就会出现性能瓶颈。
11g+:
只要在整个sql的任何一个关键字(select、update、insert、delete、merge)后面出现一次parallel(n),那么整个SQL相关的表,都会使用并行,在写法上非常的简洁,而且不会遗漏。现在新开发的应用都应该是11gR2以上了,忘了10g的写法吧。
注意:
/*+ parallel */ 或 /*+ parallel 8 */是错误的并行hint写法,这些不正确的写法会导致SQL使用一个比较大的并行度,消耗大量的系统资源。
4、并行DML
DML有4种,INSERT、DELETE、UPDATE还有MERGE,如:
insert /*+ parallel(4) */ into t1 select .... from ....;
这个写法将会在select部分使用并行度为4的并行,DML部分的并行并没有真正的启用,12c之前,DML的并行默认是关闭的,如果需要使用,必须在session级别通过下面命令开启:
alter session enable parallel dml;--推荐写法
或者
alter session force parallel dml parallel n;
--用force的语法,可以使下面的dml即使不用parallel的hint,
也会使用并行度为n的并行。
执行这个命令后,才真正开启了DML的并行。
从12c开始,启用并行DML的方法也有了改进,可以说操作更加简单了,不用alter session的方式,而是直接用enable_parallel_dml的hint启用,如:
insert /*+ enable_parallel_dml parallel(8) */ into tab_name select * from ....;
commit;
alter session enable parallel dml;
insert /*+ parallel(8) */ into tab_name select * from ....;
commit;
alter session disable parallel dml;
注意:
开启了DML的并行后,接下来的DML语句将会产生一个表锁,在commit之前,当前session不能对该表做查询和dml操作,其他session也不能对该表做DML操作。
所以建议,并行dml语句,应该在语句执行后立即commit; 然后再关闭并行dml,完整的过程应该是:
alter session enable parallel dml;
your dml;
commit;
alter session disable parallel dml;
或者
alter session force parallel dml parallel 1;
补充:
parallel的hint并不能保证sql一定会使用并行,如果优化器认为sql使用索引更高效,可能会使用索引而不使用并行。如果要确保SQL使用并行,有时可能要结合full的hint,这种情况不多见。
无论是并行,还是其他的技术,还是需要理解原理层面,知其然更要知其所以然,才能在合适的场景使用合适的技术。