Oracle Parallel Execution(并行执行)
一.
并行的实现机制是: 首先,Oracle 会创建一个进程用于协调并行服务进程之间的信息传递,这个协调进程将需要操作的数据集(比如表的数据块)分割成很多部分,称为并行处理单元,然后并行协调进程给每个并行进程分配一个数据单元。比如有四个并行服务进程,他们就会同时处理各自分配的单元,当一个并行服务进程处理完毕后,协调进程就会给它们分配另外的单元,如此反复,直到表上的数据都处理完毕,最后协调进程负责将每个小的集合合并为一个大集合作为最终的执行结果,返回给用户。
并行处理的机制实际上就是把一个要扫描的数据集分成很多小数据集,Oracle 会启动几个并行服务进程同时处理这些小数据集,最后将这些结果汇总,作为最终的处理结果返回给用户。
这种数据并行处理方式在OLAP系统中非常有用,OLAP系统的表通常来说都是非常大,如果系统的CPU比较多,让所有的CPU共同来处理这些数据,效果就会比串行执行要高的多。
然而对于OLTP系统,通常来讲,并行并不合适,原因是OLTP系统上几乎在所有的SQL操作中,数据访问路劲基本上以索引访问为主,并且返回结果集非常小,这样的SQL 操作的处理速度一般非常快,不需要启用并行。
二. 并行处理的机制
三. 读懂一个并行处理的执行计划
CREATE TABLE emp2 AS SELECT * FROM employees;
ALTER TABLE emp2 PARALLEL 2;
EXPLAIN PLAN FOR
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
--------------------------------------------------------------------------------------------------------
| Id
--------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------
The table EMP2 is scanned in parallel by one set of slaves while the aggregation for the GROUP BY is done by the second set. The PX BLOCK ITERATOR row source represents the splitting up of the table EMP2 into pieces so as to divide the scan workload between the parallel scan slaves. The PX SEND and PX RECEIVE row sources represent the pipe that connects the two slave sets as rows flow up from the parallel scan, get repartitioned through the HASH table queue, and then read by and aggregated on the top slave set. The PX SEND QC row source represents the aggregated values being sent to the QC in random (RAND) order. The PX COORDINATOR row source represents the QC or Query Coordinator which controls and schedules the parallel plan appearing below it in the plan tree.
http://download.oracle.com/docs/cd/E11882_01/server.112/e10821/ex_plan.htm#PFGRF94687
通过执行计划,我们来看一下它的执行步骤:
当使用了并行执行,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 部分是串行操作,就会出现这个情况。
四.并行执行等待事件
一般来说空闲等待可以忽略它,但是实际上空闲等待也是需要关注的,因为一个空闲的等待,它反映的是另外的资源已经超负荷运行了。 基于这个原因,在Oracle 10g里已经把PX Deq Credit: send blkd等待时间不在视为空闲等待,而是列入了Others 等待事件范围。
PX Deq Credit: send blkd 等待事件的意思是: 当并行服务进程向并行协调进程QC(也可能是上一层的并行服务进程)发送消息时,同一时间只有一个并行服务进程可以向上层进程发送消息,这时候如果有其他的并行服务进程也要发送消息,就只能等待了。 知道获得一个发送消息的信用信息(Credit),这时候会触发这个等待事件,这个等待事件的超时时间为2秒钟。
所以对于非下层的并行进程造成的等待,解决的方法就是降低每个并行执行的并行度,比如对象(表,索引)上预设的并行度或者查询Hint 指定的并行度。
五. 并行执行的使用范围
Oracle的并行技术在下面的场景中可以使用:
(1)
(2)
(3)
5.1 并行查询
(1)
(2)
(3)
如: select
SELECT
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:
有了trace文件, 我们可以用tkprof 工具,来查看trace 文件的内容。 关于tkprof 工具介绍,参考blog:
进入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.
d:/app/Administrator/diag/rdbms/orcl/orcl/trace>
5.2.2 创建索引的并行执行
一个简单的语法:create index t_ind on t(id) parallel 4;
监控这个过程和5.2.1 中表一样,需要通过10046事件。 这里就不多说了。
有关减少创建时间方法,参考blog:
总结:
使用并行方式,不论是创建表,修改表,创建索引,重建索引,他们的机制都是一样的,那就是Oracle 给每个并行服务进程分配一块空间,每个进程在自己的空间里处理数据,最后将处理完毕的数据汇总,完成SQL的操作。
5.3 并行DML 操作
会话已更改。
5.3.1 delete,update和merge 操作
5.3.2 Insert 的并行操作
六. 并行执行的设定
6.1 并行相关的初始话参数
6.1.1 parallel_min_servers=n
6.1.2 parallel_max_servers=n
6.1.3 parallel_adaptive_multi_user=true|false
6.1.4 parallel_min_percent
6.2 并行度的设定
(1)使用Hint 指定并行度。
(2)使用alter session force parallel 设定并行度。
(3)使用SQL中引用的表或者索引上设定的并行度,原则上Oracle 使用这些对象中并行度最高的那个值作为当前执行的并行度。
示例:
Oracle 默认并行度计算方式:
(1)Oracle 根据CPU的个数,RAC实例的个数以及参数parallel_threads_per_cpu的值,计算出一个并行度。
(2)对于并行访问分区操作,取需要访问的分区数为并行度。
并行度的优先级别从高到低:
实际上,并行只有才系统资源比较充足的情况下,才会取得很好的性能,如果系统负担很重,不恰当的设置并行,反而会使性能大幅下降。
七. 直接加载
在insert 的SQL中使用APPEND,如:
还可以在SQL*LOADER里面使用直接加载:
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_NA
---------- ---------- ----------
T
T
T
T
T
这里我们创建了一张表,分配了5个extents。
SQL> delete from t;
已删除979行。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA
---------- ---------- ----------
T
T
T
T
T
这里删除了表里的数据,但是查询,依然占据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_NA
---------- ---------- ----------
T
T
T
T
T
用传统方式插入,数据被分配到已有的空闲空间里。
SQL> delete from t;
已删除980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA
---------- ---------- ----------
T
T
T
T
T
删除数据,用append直接插入看一下。
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_NA
---------- ---------- ----------
T
T
T
T
T
T
T
T
T
T
已选择10行。
从结果可以看出,直接加载方式时,虽然表中有很多空的数据块,Oracle 仍然会额外的分配4个extent用于直接加载数据。
Oracle 高水位(HWM)
http://blog.csdn.net/tianlesoftware/archive/2009/10/22/4707900.aspx
7.1 直接加载和REDO
Logging模式下示例:
SQL> set autot trace stat;
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
SQL> rollback;
回退已完成。
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
Nologging模式下示例:
SQL> alter table t nologging;
表已更改。
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
SQL> rollback;
回退已完成。
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
这部分内容也可参考Blog:
http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5701596.aspx
7.2 直接加载和索引
nologging示例:
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
SQL> rollback;
回退已完成。
SQL> create index t_ind on t(table_name);
索引已创建。
SQL> insert into t select * from user_tables;
已创建980行。
统计信息
----------------------------------------------------------
SQL> rollback;
回退已完成。
SQL> insert
已创建980行。
统计信息
----------------------------------------------------------
SQL> rollback;
回退已完成。
7.3 直接加载和并行
SQL>alter session enable parallel dml;
SQL>insert into t select * from t1;
SQL>insert into t select * from t1;
注:在对insert 使用并行时,Oracle自动使用直接加载的方式进行数据加载,所以在这种情况下append是可以省略的。
7.4 直接加载和SQL*LOADER
指定加载:
指定并行和加载:
SQL*LOADER直接加载对索引的影响:
(1)索引为非约束性,直接加载可以在加载完毕后维护索引的完整性。
(2)索引为约束性索引,比如主键,直接加载仍然会将数据加载入库,但是会将索引置为unusable.
如果使用SQL*LOADER的并行直接加载选项,并且表上有索引,将导致加载失败,这是我们可以在sqlloader中指定skip_index_maintenance=true, 来允许加载完成,但是索引状态会变成unusable,需要手工rebuild.