四.并行执行等待事件
在做并行执行方面的性能优化的时候,可能会遇到如下等待时间:
PX Deq Credit: send blkd
这是一个有并行环境的数据库中,从statspack或者AWR中经常可以看到的等待事件。 在里面, 这个等待时间被列入空闲等待。 关于等待时间参考:
Oracle常见的33个等待事件
一般来说空闲等待可以忽略它,但是实际上空闲等待也是需要关注的,因为一个空闲的等待,它反映的是另外的资源已经超负荷运行了。 基于这个原因,在Oracle 10g里已经把PX Deq Credit: send blkd等待时间不在视为空闲等待,而是列入了Others等待事件范围。
PX Deq Credit: send blkd等待事件的意思是: 当并行服务进程向并行协调进程QC(也可能是上一层的并行服务进程)发送消息时,同一时间只有一个并行服务进程可以向上层进程发送消息,这时候如果有其他的并行服务进程也要发送消息,就只能等待了。 知道获得一个发送消息的信用信息(Credit),这时候会触发这个等待事件,这个等待事件的超时时间为2秒钟。
如果我们启动了太多的并行进程,实际上系统资源(CPU)或者QC无法即时处理并行服务发送的数据,那么等待将不可避免。 对于这种情况,我们就需要降低并行处理的并行度。
当出现PX Deq Credit:send blkd等待的时间很长时,我们可以通过平均等待时间来判断等待事件是不是下层的并行服务进程空闲造成的。该等待事件的超时时间是2秒,如果平均等待时间也差不多是2秒,就说明是下层的并行进程“无事所做”,处于空闲状态。 如果和2秒的差距很大,就说明不是下层并行服务超时导致的空闲等待,而是并行服务之间的竞争导致的,因为这个平均等待事件非常短,说明并行服务进程在很短时间的等待之后就可以获取资源来处理数据。
所以对于非下层的并行进程造成的等待,解决的方法就是降低每个并行执行的并行度,比如对象(表,索引)上预设的并行度或者查询Hint指定的并行度。
五.并行执行的使用范围
Oracle的并行技术在下面的场景中可以使用:
(1)Parallel Query(并行查询)
(2)Parallel DDL(并行DDL操作,如建表,建索引等)
(3)Parallel DML(并行DML操作,如insert,update,delete等)
5.1并行查询
并行查询可以在查询语句,子查询语句中使用,但是不可以使用在一个远程引用的对象上(如DBLINK)。
一个查询能够并行执行,需要满足一下条件:
(1)SQL语句中有Hint提示,比如Parallel或者Parallel_index.
(2)SQL语句中引用的对象被设置了并行属性。
(3)多表关联中,至少有一个表执行全表扫描(Full table scan)或者跨分区的Index range SCAN。
如:select/*+parallel(t 4) * from t;
5.2并行DDL操作
5.2.1表操作的并行执行
以下表操作可以使用并行执行:
CREATE TABLE … AS SELECT
ALTER TABLE … move partition
Alter table … split partition
Alter table … coalesce partition
DDL操作,我们可以通过trace文件来查看它的执行过程。
示例:
查看当前的trace文件:
/* Formatted on 2010/8/31 23:33:00 (QP5 v5.115.810.9015) */
SELECTu_dump.VALUE
||''/''
|| db_name.VALUE
||''_ora_''
|| v$process.spid
||NVL2(v$process.traceid,''_''|| v$process.traceid,NULL)
||''.trc''
"Trace File"
FROMv$parameter u_dump
CROSSJOIN
v$parameter db_name
CROSSJOIN
v$process
JOIN
v$session
ONv$process.addr=v$session.paddr
WHEREu_dump.name=''user_dump_dest''
ANDdb_name.name=''db_name''
ANDv$session.audsid=SYS_CONTEXT(''userenv'',''sessionid'');
Trace File
------------------------------------------------------------------------------
d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_5836.trc
d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_3048.trc
SQL> alter session set events ''10046 trace name context forever,level 12'';
会话已更改。
SQL> create table怀宁parallel 4 as select * from dba_objects;
表已创建。
SQL> alter session set events ''10046 trace name context off'' ;
会话已更改。
这里用到了ORACLE的event时间。 10046事件是用来跟踪SQL语句的。开启事件后,相关的信息会写道trace文件中,这也是之前我们查看trace文件名的原因。关于event事件,参考我的blog:
Oracle跟踪事件set event
有了trace文件, 我们可以用tkprof工具,来查看trace文件的内容。 关于tkprof工具介绍,参考blog:
使用Tkprof分析ORACLE跟踪文件
进入trace目录,用tkprof命令生成txt文件,然后查看txt文件。
d:/app/Administrator/diag/rdbms/orcl/orcl/trace>tkprof orcl_ora_3048.trc安庆.txt sys=no
TKPROF: Release 11.2.0.1.0 - Development on星期二8月31 23:45:25 2010
Copyright (c) 1982, 2009, Oracle and/or its affiliates.All rights reserved.
d:/app/Administrator/diag/rdbms/orcl/orcl/trace>
5.2.2创建索引的并行执行
创建索引时使用并行方式在系统资源充足的时候会使性能得到很大的提高,特别是在OLAP系统上对一些很大的表创建索引时更是如此。 以下的创建和更改索引的操作都可以使用并行:
Create index
Alter index … rebuild
Alter index … rebuild partition
Alter index … split partition
一个简单的语法:create index t_ind on t(id) parallel 4;
监控这个过程和5.2.1中表一样,需要通过10046事件。 这里就不多说了。
有关减少创建时间方法,参考blog:
如何加快建index索引的时间
总结:
使用并行方式,不论是创建表,修改表,创建索引,重建索引,他们的机制都是一样的,那就是Oracle给每个并行服务进程分配一块空间,每个进程在自己的空间里处理数据,最后将处理完毕的数据汇总,完成SQL的操作。
5.3并行DML操作
Oracle可以对DML操作使用并行执行,但是有很多限制。 如果我们要让DML操作使用并行执行,必须显示地在会话里执行如下命令:
SQL> alter session enable parallel dml;
会话已更改。
只有执行了这个操作,Oracle才会对之后符合并行条件的DML操作并行执行,如果没有这个设定,即使SQL中指定了并行执行,Oracle也会忽略它。
5.3.1 delete,update和merge操作
Oracle对Delete,update,merge的操作限制在,只有操作的对象是分区表示,Oracle才会启动并行操作。原因在于,对于分区表,Oracle会对每个分区启用一个并行服务进程同时进行数据处理,这对于非分区表来说是没有意义的。
5.3.2 Insert的并行操作
实际上只有对于insert into … select …这样的SQL语句启用并行才有意义。 对于insert into .. values…并行没有意义,因为这条语句本身就是一个单条记录的操作。
Insert并行常用的语法是:
Insert /*+parallel(t 2) */ into t select /*+parallel(t1 2) */ * from t1;
这条SQL语句中,可以让两个操作insert和select分别使用并行,这两个并行是相互独立,互补干涉的,也可以单独使用其中的一个并行。
六.并行执行的设定
6.1并行相关的初始话参数
6.1.1 parallel_min_servers=n
在初始化参数中设置了这个值,Oracle在启动的时候就会预先启动N个并行服务进程,当SQL执行并行操作时,并行协调进程首先根据并行度的值,在当前已经启动的并行服务中条用n个并行服务进程,当并行度大于n时,Oracle将启动额外的并行服务进程以满足并行度要求的并行服务进程数量。
6.1.2 parallel_max_servers=n
如果并行度的值大于parallel_min_servers或者当前可用的并行服务进程不能满足SQL的并行执行要求,Oracle将额外创建新的并行服务进程,当前实例总共启动的并行服务进程不能超过这个参数的设定值。
6.1.3 parallel_adaptive_multi_user=true|false
Oracle 10g R2下,并行执行默认是启用的。 这个参数的默认值为true,它让Oracle根据SQL执行时系统的负载情况,动态地调整SQL的并行度,以取得最好的SQL执行性能。
6.1.4 parallel_min_percent
这个参数指定并行执行时,申请并行服务进程的最小值,它是一个百分比,比如我们设定这个值为50.当一个SQL需要申请20个并行进程时,如果当前并行服务进程不足,按照这个参数的要求,这个SQL比如申请到20*50%=10个并行服务进程,如果不能够申请到这个数量的并行服务,SQL将报出一个ORA-12827的错误。
当这个值设为Null时,表示所有的SQL在做并行执行时,至少要获得两个并行服务进程。
6.2并行度的设定
并行度可以通过以下三种方式来设定:
(1)使用Hint指定并行度。
(2)使用alter session force parallel设定并行度。
(3)使用SQL中引用的表或者索引上设定的并行度,原则上Oracle使用这些对象中并行度最高的那个值作为当前执行的并行度。
示例:
SQL>Select /*+parallel(t 4) */ count(*) from t;
SQL>Alter table t parallel 4;
SQL>Alter session force parallel query parallel 4;
Oracle默认并行度计算方式:
(1)Oracle根据CPU的个数,RAC实例的个数以及参数parallel_threads_per_cpu的值,计算出一个并行度。
(2)对于并行访问分区操作,取需要访问的分区数为并行度。
并行度的优先级别从高到低:
Hint->alter session force parallel->表,索引上的设定->系统参数
实际上,并行只有才系统资源比较充足的情况下,才会取得很好的性能,如果系统负担很重,不恰当的设置并行,反而会使性能大幅下降。
七.直接加载
在执行数据插入或者数据加载的时候,可以通过append hint的方式进行数据的直接加载。
在insert的SQL中使用APPEND,如:
Insert /*+append */ into t select * from t1;
还可以在SQL*LOADER里面使用直接加载:
Sqlldr userid=user/pwd control=load.ctl direct=true
Oracle执行直接加载时,数据直接追加到数据段的最后,不需要花费时间在段中需找空间,数据不经过data buffer直接写到数据文件中,效率要比传统的加载方式高。
示例:
SQL> create table t as select * from user_tables;
表已创建。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name=''T'';
SEGMENT_NAEXTENT_IDBYTES
---------- ---------- ----------
T065536
T165536
T265536
T365536
T465536
这里我们创建了一张表,分配了5个extents。
SQL> delete from t;
已删除979行。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name=''T'';
SEGMENT_NAEXTENT_IDBYTES
---------- ---------- ----------
T065536
T165536
T265536
T365536
T465536
这里删除了表里的数据,但是查询,依然占据5个extents。因为delete不会收缩表空间,不能降低高水位。
SQL> insert into t select * from user_tables;
已创建980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name=''T'';
SEGMENT_NAEXTENT_IDBYTES
---------- ---------- ----------
T065536
T165536
T265536
T365536
T465536
用传统方式插入,数据被分配到已有的空闲空间里。
SQL> delete from t;
已删除980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name=''T'';
SEGMENT_NAEXTENT_IDBYTES
---------- ---------- ----------
T065536
T165536
T265536
T365536
T465536
删除数据,用append直接插入看一下。
SQL> insert /*+append */ into t select * from user_tables;
已创建980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name=''T'';
SEGMENT_NAEXTENT_IDBYTES
---------- ---------- ----------
T065536
T165536
T265536
T365536
T465536
T565536
T665536
T765536
T865536
T965536
已选择10行。
从结果可以看出,直接加载方式时,虽然表中有很多空的数据块,Oracle仍然会额外的分配4个extent用于直接加载数据。
直接加载的数据放在表的高水位(High water Mark:hwm)以上,当直接加载完成后,Oracle将表的高水位线移到新加入的数据之后,这样新的数据就可以被用户使用了。
Oracle高水位(HWM)