并行:把一个工作分成几份,分给不同进程同时进行处理。 进程层面
并发:多个会话同时进行访问,就是通常所说并发数。会话层面
数据库版本
LEO1@LEO1> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
一、 给出一个2表关联的并行查询执行计划,并画出并行数据流图
(1)并行应用场合:
1.OLAP 业务模式
首先说明一个我们经常混洗的概念OLAP和数据仓库是不是一个东西。
回答:NO
OLAP是一种业务模式,是一种批量加载批量检索的业务模式,例如 在线数据分析系统。
数据仓库:是支撑这种业务模式的底层数据库。
2.系统资源相对空闲
当系统的CPU较多 IO负载不高 内存够大的时候,可以使用并行操作,需要考虑资源平衡。
3.数据符合并行特点
这个说明是什么呢,就是你所操作的数据没有串行化,可以拆分,同时对不同部分数据进行操作,
如果是那种只有计算出前者才能统计后者的流程就不适合使用并行操作了。
例如统计行数就可以使用并行,让10个进程分别统计不同区域的行数最后把结果合并起来返回给用户。
(2)首先明示一下使用并行的3种方法
1.hints 方式 临时有效
select /*+ parallel(leo1 2) */ count(*) from leo1;
2.alter table 对象级别定义并行 直接修改对象属性 长期有效
alter table leo1 parallel 4; 定义leo1表并行度为4
3.alter session force parallel 会话级别定义并行 会话生命期中有效
alter session force parallel query parallel 4; 强制定义并行度为4
通常/*+ parallel(leo1 4) */
4.并行查询和并行DDL可以无障碍使用并行,如果想使用并行DML,就需要启动会话DML并行功能
alter session enable parallel dml;
(3)实验
现在我们做一个并行操作,分析一下并行执行计划流程,感性的感受一下并行的魅力
LEO1@LEO1> drop table leo1 purge; 清理环境
Table dropped.
LEO1@LEO1> drop table leo2 purge;
Table dropped.
LEO1@LEO1> create table leo1 as select * from dba_objects; 创建leo1表
Table created.
LEO1@LEO1> create table leo2 as select * from leo1; 模拟leo1创建leo2表
Table created.
LEO1@LEO1> execute dbms_stats.gather_table_stats(ownname=>'LEO1',tabname=>'LEO1',
method_opt=>'for all indexed columns size 254');
PL/SQL procedure successfully completed.
LEO1@LEO1> execute dbms_stats.gather_table_stats(ownname=>'LEO1',tabname=>'LEO2',
method_opt=>'for all indexed columns size 254');
PL/SQL procedure successfully completed.
对leo1和leo2进行全表整体分析包括数据分布情况分析(数据倾斜程度,即直方图)
Tips
如果想让n个表关联查询并且都启并行的话,hints如何写呢,请看下面
/*+ parallel(leo1,leo2,2) */ 对吗? 当然不对
/*+ parallel(leo1 leo2,2) */ 对吗? 当然也不对
/*+ parallel(leo1,2) parallel(leo2,2) */ 对吗? Yes 亲们要看好哦
/*+ parallel(leo1,2) parallel(leo2,2) parallel(leo3,2) ……*/ 后面同理延续
LEO1@LEO1> select /*+ parallel(leo1,2) parallel(leo2,2) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
Execution Plan 并行度为2 执行计划
----------------------------------------------------------
Plan hash value: 2718975204
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 320 (1)| 00:00:04 | | | |
| 1 | SORT AGGREGATE | | 1 | 26 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10001 | 1 | 26 | | | Q1,01 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 26 | | | Q1,01 | PCWP | |
|* 5 | HASH JOIN | | 72017 | 1828K| 320 (1)| 00:00:04 | Q1,01 | PCWP | |
| 6 | PX BLOCK ITERATOR | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWC | |
| 7 | TABLE ACCESS FULL | LEO1 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWP | |
| 8 | PX RECEIVE | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWP | |
| 9 | PX SEND BROADCAST | :TQ10000 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | P->P | BROADCAST |
| 10 | PX BLOCK ITERATOR | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | PCWC | |
| 11 | TABLE ACCESS FULL| LEO2 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | PCWP | |
-------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("LEO1"."OBJECT_ID"="LEO2"."OBJECT_ID")
解释一下并行执行计划步骤,并行执行计划应该从下往上读,当看见PX(parallel execution)关键字说明使用了并行技术
1. | 7 | TABLE ACCESS FULL | LEO1 | 首先对leo1表进行全表扫描
2. | 6 | PX BLOCK ITERATOR | 并行进程以迭代iterator的方式分割数据块
3. | 11 | TABLE ACCESS FULL| LEO2 | 然后对leo2表进行全表扫描
4. | 10 | PX BLOCK ITERATOR |并行进程以迭代iterator的方式分割数据块
5. | 9 | PX SEND BROADCAST | :TQ10000 |并行进程以广播方式发送扫描结果
6. | 8 | PX RECEIVE |并行进程接收发送过来的结果
7. |* 5 | HASH JOIN |在这里把leo1 leo2表扫描结果做哈希关联
8. | 4 | SORT AGGREGATE|将哈希关联结果做count统计操作
9. | 3 | PX SEND QC (RANDOM)| :TQ10001 |按照随机顺序发送给并行协调进程QC(query coordinator)整合结果
10. | 2 | PX COORDINATOR |接收数据
11. | 1 | SORT AGGREGATE |整合结果
12. | 0 | SELECT STATEMENT |完毕后QC将最终结果返回给用户
说明并行执行计划中特有的IN-OUT列的含义(指明了操作中数据流的方向)
Parallel to Serial(P->S): 表示一个并行操作向一个串行操作发送数据,通常是将并行结果发送给并行
调度进程QC进行汇总 例如 PX SEND QC (RANDOM)
Serial to Parallel(S->P): 表示一个串行操作向一个并行操作发送数据,如果select部分是串行操作,就会出现这个情况
Parallel to Parallel(P->P):表示一个并行操作向另一个并行操作发送数据,一般是并行父进程与并行子进程之间的数据交流
Parallel Combined with parent(PCWP): 数据在同一组的并行进程之间传递
Parallel Combined with Child(PCWC): 数据在不同组的并行进程之间传递
下面我们从v$pq_tqstat动态性能视图中查看一下并行进程的工作量平衡情况
LEO1@LEO1> select dfo_number,tq_id,server_type,num_rows,bytes,process from v$pq_tqstat;
DFO_NUMBER TQ_ID SERVER_TYPE NUM_ROWS BYTES PROCESS
---------- ---------- -------------------- ---------- ---------- ----------------------------------------------------------
1 0 Consumer 72017 422219 P000
1 1 Producer 1 36 P000
1 0 Consumer 72017 422219 P001
1 1 Producer 1 36 P001
PROCESS:P000 P001 是2个进程号,说明我们启动了2个并行进程和我们设定的并行度一致
SERVER_TYPE:进程在处理中扮演的角色
Producer 扮演并行服务角色,干活的(具体处理操作)
Consumer 扮演并行协调角色,分配任务和结果合并
NUM_ROWS:上面角色处理的行数
BYTES:行数所占的空间字节
TQ_ID:table queue ID 区分同一个进程扮演2个角色时的不同操作(来自官方文档)和执行计划中TQ同理
DFO_NUMBER:1 = 第一次并行操作 2 = 第二次并行操作 3 = 第三次并行操作
第一次并行操作牵涉到两个并行进程 P000 P001
DFO (data flow operator)操作流程
Tips
LEO1@LEO1> select distinct sid from v$mystat;
SID
------------------
133
LEO1@LEO1> select sid,PDML_STATUS,PDDL_STATUS,PQ_STATUS from v$session;
SID PDML_STA PDDL_STA PQ_STATU
---------- -------- -------- ---------------- -------- ----
133 DISABLED ENABLED ENABLED
我们可以利用v$session中的PDML_STATUS,PDDL_STATUS,PQ_STATUS查看当前会话的默认并行状态
二、 就自己本机的硬件情况,通过SQL示例,来找到最优的并行度
(1)并行度:就是oracle在进行并行处理时,会启动几个并行服务进程来同时处理数据,注意看看数据需要几步处理,每一步都启n个进程而不是只启n个进程
并行度设定:一般来讲一个CPU内核可以支撑一个并行度,一台多核服务器中通常采用CPU核数50%来设定并行度,余下的CPU处理其他程序
并行度与硬件关系密切,同样并行度在不同硬件上体现的效果是截然不同的
并行度与并发数关系:总并行数=并行度*并发数,当并行度确立后,并发数越多总并行数越高
(2)实验
我使用的是me的ACER小本本,例举一下配置
英特尔@酷睿 i3-370M 双核四线程
14LED显示屏
NVIDIA GeForce@GT 520M
4G DDR3
500GB
DVD-SuperMulti刻录
Acer Nplify 802.11b/g/n
6芯锂离子电池
为了对比方便,我还是使用刚才SQL语句只是变化不同的并行度,来对比执行计划找到最优的并行度
并行度设置成2
LEO1@LEO1> select /*+ parallel(leo1,2) parallel(leo2,2) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2718975204
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 320 (1)| 00:00:04 | | | |
| 1 | SORT AGGREGATE | | 1 | 26 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10001 | 1 | 26 | | | Q1,01 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 26 | | | Q1,01 | PCWP | |
|* 5 | HASH JOIN | | 72017 | 1828K| 320 (1)| 00:00:04 | Q1,01 | PCWP | |
| 6 | PX BLOCK ITERATOR | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWC | |
| 7 | TABLE ACCESS FULL | LEO1 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWP | |
| 8 | PX RECEIVE | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,01 | PCWP | |
| 9 | PX SEND BROADCAST | :TQ10000 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | P->P | BROADCAST |
| 10 | PX BLOCK ITERATOR | | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | PCWC | |
| 11 | TABLE ACCESS FULL| LEO2 | 72017 | 914K| 160 (1)| 00:00:02 | Q1,00 | PCWP | |
-------------------------------------------------------------------------------------------------------------------
性能指标Cost=160 Time=00:00:02
并行度设置成4
LEO1@LEO1> select /*+ parallel(leo1,4) parallel(leo2,4) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 589148148
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 160 (1)| 00:00:02 | | | |
| 1 | SORT AGGREGATE | | 1 | 26 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | 26 | | | Q1,02 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 26 | | | Q1,02 | PCWP | |
|* 5 | HASH JOIN | | 72017 | 1828K| 160 (1)| 00:00:02 | Q1,02 | PCWP | |
| 6 | PX RECEIVE | | 72017 | 914K| 80 (0)| 00:00:01 | Q1,02 | PCWP | |
| 7 | PX SEND HASH | :TQ10000 | 72017 | 914K| 80 (0)| 00:00:01 | Q1,00 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | 72017 | 914K| 80 (0)| 00:00:01 | Q1,00 | PCWC | |
| 9 | TABLE ACCESS FULL| LEO1 | 72017 | 914K| 80 (0)| 00:00:01 | Q1,00 | PCWP | |
| 10 | PX RECEIVE | | 72017 | 914K| 80 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10001 | 72017 | 914K| 80 (0)| 00:00:01 | Q1,01 | P->P | HASH |
| 12 | PX BLOCK ITERATOR | | 72017 | 914K| 80 (0)| 00:00:01 | Q1,01 | PCWC | |
| 13 | TABLE ACCESS FULL| LEO2 | 72017 | 914K| 80 (0)| 00:00:01 | Q1,01 | PCWP | |
-------------------------------------------------------------------------------------------------------------------
性能指标Cost=80 Time=00:00:01
LEO1@LEO1> select dfo_number,tq_id,server_type,num_rows,bytes,process from v$pq_tqstat;
DFO_NUMBER TQ_ID SERVER_TYPE NUM_ROWS BYTES PROCESS
---------- ---------- -------------------- ---------- ---------- ----------------------------------------------------------
1 0 Consumer 72017 422219 P000
1 1 Producer 1 36 P000
1 0 Consumer 72017 422219 P001
1 1 Producer 1 36 P001
1 0 Producer 71650 418494 P002
1 0 Producer 72384 425944 P003
1 1 Consumer 2 72 QC
PROCESS:P000 P001 P002 P003 说明我们启动了4个并行进程
就Cost和Time指标而言4比2个并行度效率要高一倍
并行度设置成8
LEO1@LEO1> select /*+ parallel(leo1,8) parallel(leo2,8) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 589148148
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 80 (0)| 00:00:01 | | | |
| 1 | SORT AGGREGATE | | 1 | 26 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | 26 | | | Q1,02 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 26 | | | Q1,02 | PCWP | |
|* 5 | HASH JOIN | | 72017 | 1828K| 80 (0)| 00:00:01 | Q1,02 | PCWP | |
| 6 | PX RECEIVE | | 72017 | 914K| 40 (0)| 00:00:01 | Q1,02 | PCWP | |
| 7 | PX SEND HASH | :TQ10000 | 72017 | 914K| 40 (0)| 00:00:01 | Q1,00 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | 72017 | 914K| 40 (0)| 00:00:01 | Q1,00 | PCWC | |
| 9 | TABLE ACCESS FULL| LEO1 | 72017 | 914K| 40 (0)| 00:00:01 | Q1,00 | PCWP | |
| 10 | PX RECEIVE | | 72017 | 914K| 40 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10001 | 72017 | 914K| 40 (0)| 00:00:01 | Q1,01 | P->P | HASH |
| 12 | PX BLOCK ITERATOR | | 72017 | 914K| 40 (0)| 00:00:01 | Q1,01 | PCWC | |
| 13 | TABLE ACCESS FULL| LEO2 | 72017 | 914K| 40 (0)| 00:00:01 | Q1,01 | PCWP | |
-------------------------------------------------------------------------------------------------------------------性能指标Cost=53
性能指标Cost=40 代价又减少了一半
并行度设置成16
LEO1@LEO1> select /*+ parallel(leo1,16) parallel(leo2,16) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 589148148
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 40 (0)| 00:00:01 | | | |
| 1 | SORT AGGREGATE | | 1 | 26 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10002 | 1 | 26 | | | Q1,02 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 26 | | | Q1,02 | PCWP | |
|* 5 | HASH JOIN | | 72017 | 1828K| 40 (0)| 00:00:01 | Q1,02 | PCWP | |
| 6 | PX RECEIVE | | 72017 | 914K| 20 (0)| 00:00:01 | Q1,02 | PCWP | |
| 7 | PX SEND HASH | :TQ10000 | 72017 | 914K| 20 (0)| 00:00:01 | Q1,00 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | 72017 | 914K| 20 (0)| 00:00:01 | Q1,00 | PCWC | |
| 9 | TABLE ACCESS FULL| LEO1 | 72017 | 914K| 20 (0)| 00:00:01 | Q1,00 | PCWP | |
| 10 | PX RECEIVE | | 72017 | 914K| 20 (0)| 00:00:01 | Q1,02 | PCWP | |
| 11 | PX SEND HASH | :TQ10001 | 72017 | 914K| 20 (0)| 00:00:01 | Q1,01 | P->P | HASH |
| 12 | PX BLOCK ITERATOR | | 72017 | 914K| 20 (0)| 00:00:01 | Q1,01 | PCWC | |
| 13 | TABLE ACCESS FULL| LEO2 | 72017 | 914K| 20 (0)| 00:00:01 | Q1,01 | PCWP | |
-------------------------------------------------------------------------------------------------------------------
性能指标Cost=20 代价又减少了一半
并行度设置成32
LEO1@LEO1> select /*+ parallel(leo1,32) parallel(leo2,32) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
性能指标Cost=10 代价又减少了一半
并行度设置成64
LEO1@LEO1> select /*+ parallel(leo1,64) parallel(leo2,64) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
性能指标Cost=5 代价又减少了一半
并行度设置成128
LEO1@LEO1> select /*+ parallel(leo1,128) parallel(leo2,128) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
性能指标Cost=2 代价又减少了一半
并行度设置成256
LEO1@LEO1> select /*+ parallel(leo1,128) parallel(leo2,128) */ count(*) from leo1,leo2
where leo1.object_id=leo2.object_id;
性能指标Cost=2 好一致了
小结:当并行度设置成256时Cost不在减少了,说明此时并行度最优。说明一下我的这张表只有7w多条数据,有可能数据量比较少CPU可以很快的执行完毕,所以Cost也比较小。
三 、针对PARALLEL_DEGREE_POLICY的三个值,分别演示它们的效果
(1)自动并行度策略PARALLEL_DEGREE_POLICY是oracle11g新特性,通过它可以设置并行度策略
这个参数有三个值:manual 手动方式,也是默认方式,oracle不会擅自调整并行度
limited 限制方式
auto 自动方式
(2)实验
LEO1@LEO1> drop table leo3 purge; 清理环境
Table dropped.
LEO1@LEO1> drop table leo4 purge;
Table dropped.
LEO1@LEO1> create table leo3 as select * from dba_objects; 创建leo3表
Table created.
LEO1@LEO1> create table leo4 as select * from dba_objects; 创建leo4表
Table created.
parallel_degree_policy=manual
如果我们设置manual,oracle不会参与调整并行度,不管资源负载如何,并行度是多少就用多少
第一种设置方式
LEO1@LEO1> alter table leo3 parallel 4; 直接指定leo3表并行度为4
Table altered.
对象级别定义并行,直接修改对象属性,长期有效
LEO1@LEO1> select table_name,degree from user_tables where table_name in ('LEO3'); 并行度已经调整完毕
TABLE_NAME DEGREE
------------------------------ -------------------------------
LEO3 4
第二种设置方式
LEO1@LEO1> alter table leo3 parallel(degree 4); 这种方法和上面方法同理
第一种设置方式
LEO1@LEO1> alter table leo4 parallel; 设置leo4表的并行度为default
Table altered.
第二种设置方式
LEO1@LEO1> alter table leo4 parallel(degree default); 同理也是设置为default
Table altered.
第三种设置方式 hint
select /*+ parallel */ * from leo4; 不写并行度就是使用oracle默认并行度(临时有效)
这三种方式我们选择其一即可
LEO1@LEO1> select table_name,degree from user_tables where table_name in ('LEO3','LEO4');
TABLE_NAME DEGREE
------------------------------ -------------------- --------------------
LEO3 4
LEO4 DEFAULT 默认并行度
设置自动并行度为manual
LEO1@LEO1> alter session set parallel_degree_policy=manual;
Session altered.
LEO1@LEO1> select count(*) from leo3; 统计leo3表使用并行操作
COUNT(*)
------------------
72017
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- ------------------------------ ---------- ----
Allocation Height 4 0
使用并行度是4,oracle没有改变并行度
LEO1@LEO1> select count(*) from leo4; 这张表是使用oracle默认并行度
COUNT(*)
----------
72018
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- -------------
Allocation Height 4 0
并行度是4,oracle还是使用默认并行度
parallel_degree_policy=limited
如果我们设置limited
当有直接指定并行度时继续使用
当表是使用oracle默认并行度时,oracle会根据资源负载自动评估调整并行度
LEO1@LEO1> alter table leo3 parallel(degree 6); 我把leo3表并行度调整为6
Table altered.
LEO1@LEO1> alter table leo4 parallel(degree default); leo4还是使用oracle默认并行度
Table altered.
LEO1@LEO1> select table_name,degree from user_tables where table_name in ('LEO3','LEO4');
TABLE_NAME DEGREE 进行检查
---------- --------------------
LEO3 6
LEO4 DEFAULT
设置自动并行度为limited
LEO1@LEO1> alter session set parallel_degree_policy=limited;
Session altered.
LEO1@LEO1> select count(*) from leo3; 统计leo3表使用并行操作
COUNT(*)
----------
72017
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- ------------------------ ---------- ---------
Allocation Height 6 0
使用并行度是6,oracle没有改变并行度
LEO1@LEO1> select count(*) from leo4; 使用oracle默认并行度
COUNT(*)
----------------
72018
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- ------------------ ---------- -------------
Allocation Height 0 0
这回oracle改变了并行度=0,因为oracle觉得不使用并行也能有很好的效果
parallel_degree_policy=auto
如果我们设置auto,不论是直接指定的并行度还是使用oracle默认并行度,oracle都会进行干预调整,oracle会根据资源负载情况来动态调整并行度。
设置自动并行度为auto
LEO1@LEO1> alter session set parallel_degree_policy=auto;
Session altered.
LEO1@LEO1> select table_name,degree from user_tables where table_name in ('LEO3','LEO4');
TABLE_NAME DEGREE
---------- --------------------
LEO3 6
LEO4 DEFAULT
LEO1@LEO1> select count(*) from leo3;
COUNT(*)
----------
72017
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- -------------
Allocation Height 0 0
LEO1@LEO1> select count(*) from leo4;
COUNT(*)
----------
72018
LEO1@LEO1> select * from v$pq_sesstat where statistic='Allocation Height';
STATISTIC LAST_QUERY SESSION_TOTAL
------------------------------ ---------- -------------
Allocation Height 0 0
小结:无论是直接指定并行度还是使用默认并行度,oracle都调整为0,这是因为oracle认为数据量较小(7w)没有必要使用并行技术。
四 、用一个并行的SQL示例,比较10391事件和 V$PQ_TQSTAT结果的异同
10391事件可以跟踪整个并行流程,我们查看10391事件trace文件就可以知道sql语句并行执行情况
第一步 第二步 第三步 第四步
LEO1@LEO1> drop table leo5 purge; 清理环境
Table dropped.
LEO1@LEO1> create table leo5 as select * from dba_objects; 创建leo5表
Table created.
LEO1@LEO1> execute dbms_stats.gather_table_stats(ownname=>'LEO1',tabname=>'LEO5') 表分析
PL/SQL procedure successfully completed.
LEO1@LEO1> alter session set events '10391 trace name context forever,level 12'; 启动10391事件
Session altered.
在执行下面3条语句的时候记下当前时间,干什么呢后面会揭晓(非常重要哦)
2013-01-25 15:25 这是我的时间
LEO1@LEO1> select /*+ parallel(leo5,4) */ count(*) from leo5; 执行3次sql语句
COUNT(*)
----------
72011
LEO1@LEO1> select /*+ parallel(leo5,4) */ count(*) from leo5;好在10391事件trace文件中找到并行信息
COUNT(*)
----------
72011
LEO1@LEO1> select /*+ parallel(leo5,4) */ count(*) from leo5;我们执行几次就要在trace文件中找到几段
COUNT(*)
----------
72011
下面还可以执行一些其他SQL语句用于刷trace,后面有解释为什么
LEO1@LEO1> alter session set events '10391 trace name context off'; 关闭10391事件
Session altered.
LEO1@LEO1> select name,value from v$diag_info where name='Default Trace File'; 当前会话写入trace文件名
NAME VALUE
-------------------------------------------------- -------------------------------------------------------------------------------
Default Trace File /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_16433.trc
[oracle@leonarding1 trace]$ pwd
/u01/app/oracle/diag/rdbms/leo1/LEO1/trace oracle 11g和oracle 10g trace文件所在目录不同请注意
LEO1@LEO1> !vim /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_16433.trc 打开trace文件选取有用信息,真的有可用信息吗?真的嘛?
这时你可能会发现从上找到下,翻来覆去的找啊找,就是没有并行salve进程信息,难道oracle 11g不把并行信息写入trace文件嘛,这是真的嘛?=> NO不要相信你看到的,真理往往站在少数人身边。那大家会说并行信息到底在哪里啊在哪里?其实oracle跟我们玩了一次躲猫猫,它把信息藏在了log buffer cache 中,因为还没有刷到trace文件里,所以我们才没看到,那大家进一步会问oracle多长时间清理一次缓冲区脏数据呢,反正我的oracle 11g数据库大约每11分钟刷一次(oracle 10g相对较短所以大家在10g上会立刻看到),这也和缓冲区中数据量有关,如果在生产环境中不停的产生trace log可能时间间隔会缩短,只有把并行信息刷到trace文件中,我们才能看到,这就是原因所在!
ORACLE 11G版
2013-01-25 15:25
LEO1@LEO1> select /*+ parallel(leo5,4) */ count(*) from leo5;
*** 2013-01-25 15:25:32.042
kxfrDmpUpdSys
allocated slave set: nsset:1 nbslv:4 tinst=1 ipq=0
Slave set 0: #nodes:1
Min # slaves 4: Max # slaves:4
List of Slaves:
slv: 0 nid:0 instid:1 sid:00
slv: 1 nid:0 instid:1 sid:01
slv: 2 nid:0 instid:1 sid:02
slv: 3 nid:0 instid:1 sid:03
List of Nodes:
node 0
这是第一条语句的并行信息,对着时间找比较容易,使用了4个slave进程
ORACLE 10G版
kxfrDmpUpdSys
allocated slave set: nsset:1 nbslv:4
Slave set 0: #nodes:1
Min # slaves 4: Max # slaves:4
List of Slaves:
slv 0 nid:0
slv 1 nid:0
slv 2 nid:0
slv 3 nid:0
List of Nodes:
node 0
11G要比10G的多些信息,包括实例信息 会话信息等
*** 2013-01-25 15:25:34.115
dumping system information
arch:255 (unknown)
sess:133 myiid:1 mynid:1 ninst:1 maxiid:1, mnodes:0
Instances running on that system:
inum:0 iid:1
kxfrDmpUpdSys
allocated slave set: nsset:1 nbslv:4 tinst=1 ipq=0
Slave set 0: #nodes:1
Min # slaves 4: Max # slaves:4
List of Slaves:
slv: 0 nid:0 instid:1 sid:00
slv: 1 nid:0 instid:1 sid:01
slv: 2 nid:0 instid:1 sid:02
slv: 3 nid:0 instid:1 sid:03
List of Nodes:
node 0
这是第二条语句的并行信息
*** 2013-01-25 15:25:37.975
dumping system information
arch:255 (unknown)
sess:133 myiid:1 mynid:1 ninst:1 maxiid:1, mnodes:0
Instances running on that system:
inum:0 iid:1
kxfrDmpUpdSys
allocated slave set: nsset:1 nbslv:4 tinst=1 ipq=0
Slave set 0: #nodes:1
Min # slaves 4: Max # slaves:4
List of Slaves:
slv: 0 nid:0 instid:1 sid:00
slv: 1 nid:0 instid:1 sid:01
slv: 2 nid:0 instid:1 sid:02
slv: 3 nid:0 instid:1 sid:03
List of Nodes:
node 0
这是第三条语句的并行信息
比较10391事件和 V$PQ_TQSTAT视图
LEO1@LEO1> select dfo_number,tq_id,server_type,num_rows,bytes,process from v$pq_tqstat;
DFO_NUMBER TQ_ID SERVER_TYPE NUM_ROWS BYTES PROCESS
---------- ---------- -------------------- ---------- ---------- --------------------
1 0 Producer 1 36 P003
1 0 Producer 1 36 P001
1 0 Producer 1 36 P002
1 0 Producer 1 36 P000
1 0 Consumer 4 144 QC
都显示使用了4个并行服务进程
小结:本小题做起来并不难,但往往得不到自己想要的结果,做了一个下午终于拨云见日感慨万千,赋诗一首,留念于此!走起
遇到问题误急躁
想想这是为何因
多问朋友多交流
答案自然来敲门
五、 分别演示一个DDL和DML操作的并行执行示例
(1) 并行常用于:1.FTS_Full Table Scan
2.IFFS_Index Fast Full Scan
3.分区表
(2)这个小题在我的一篇blog中有非常详细阐述和实验,感兴趣的朋友可以去看一看
《oracle 并行原理深入解析及案例精粹》http://f.dataguru.cn/thread-16348-1-1.html
(3)这里我把需要注意的地方和一些应用场合跟大家一起交流交流
并行查询和并行DDL可以无障碍使用并行,如果想使用并行DML,就需要启动会话DML并行功能
alter session enable parallel dml;
(4)实验
DDL并行测试
如果想捕捉DDL并行信息,我们可以采用10046事件来过滤并行信息,因为10046事件记录了sql解析、执行、取操作的性能指标和等待事件,在等待事件中我们就可以看到PX事件来说明DDL的并行操作
LEO1@LEO1> drop table leo6 purge; 清理环境
Table dropped.
LEO1@LEO1> alter session set events '10046 trace name context forever,level 12'; 启动10046事件
Session altered.
LEO1@LEO1> create table leo6 parallel 4 as select * from dba_objects; 使用4个并行进程来创建表
Table created.
LEO1@LEO1> create index leo6_index on leo6(object_id) parallel 4; 使用4个并行进程来创建索引
Index created.
LEO1@LEO1> alter index leo6_index rebuild parallel 4; 重建索引可以这种写法
Index altered.
LEO1@LEO1> alter session set events '10046 trace name context off'; 关闭10046事件
Session altered.
LEO1@LEO1> select name,value from v$diag_info where name='Default Trace File'; 当前会话写入trace文件名
NAME VALUE
-------------------------------------------------- -------------------------------------------------------------------------------
Default Trace File /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_16433.trc
注:oracle提供了一个tkprof工具来对trace文件进行格式化翻译,过滤出有用的信息
LEO1@LEO1> !tkprof /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/LEO1_ora_16433.trc
/u01/app/oracle/diag/rdbms/leo1/LEO1/trace/10046.txt sys=no
TKPROF: Release 11.2.0.1.0 - Development on Fri Jan 25 17:21:09 2013
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
LEO1@LEO1> !vim /u01/app/oracle/diag/rdbms/leo1/LEO1/trace/10046.txt 查看日志
create table leo6 parallel 4 as select * from dba_objects 我只把并行信息截取出来
Rows Row Source Operation
------- ---------------------------------------------------
4 PX COORDINATOR (cr=1347 pr=0 pw=0 time=365787 us)
0 PX SEND QC (RANDOM) :TQ20001 (cr=0 pr=0 pw=0 time=0 us cost=132 size=14151348 card=68364)
0 LOAD AS SELECT (cr=0 pr=0 pw=0 time=0 us)
0 VIEW DBA_OBJECTS (cr=0 pr=0 pw=0 time=0 us cost=132 size=14151348 card=68364)
0 UNION-ALL (cr=0 pr=0 pw=0 time=0 us)
0 TABLE ACCESS BY INDEX ROWID SUM$ (cr=2 pr=0 pw=0 time=0 us cost=0 size=26 card=1)
1 INDEX UNIQUE SCAN I_SUM$_1 (cr=1 pr=0 pw=0 time=0 us cost=0 size=0 card=1)(object id 956)
0 TABLE ACCESS BY INDEX ROWID OBJ$ (cr=0 pr=0 pw=0 time=0 us cost=3 size=30 card=1)
0 INDEX RANGE SCAN I_OBJ1 (cr=0 pr=0 pw=0 time=0 us cost=2 size=0 card=1)(object id 36)
0 BUFFER SORT (cr=0 pr=0 pw=0 time=0 us)
0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us)
0 PX SEND ROUND-ROBIN :TQ20000 (cr=0 pr=0 pw=0 time=0 us)
72011 FILTER (cr=1342 pr=0 pw=0 time=1481001 us)
72877 PX COORDINATOR (cr=9 pr=0 pw=0 time=1519912 us)
0 PX SEND QC (RANDOM) :TQ10002 (cr=0 pr=0 pw=0 time=0 us cost=73 size=9030052 card=72823)
0 HASH JOIN (cr=0 pr=0 pw=0 time=0 us cost=73 size=9030052 card=72823)
0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us cost=2 size=1584 card=88)
0 PX SEND BROADCAST :TQ10001 (cr=0 pr=0 pw=0 time=0 us cost=2 size=1584 card=88)
0 PX BLOCK ITERATOR (cr=0 pr=0 pw=0 time=0 us cost=2 size=1584 card=88)
0 TABLE ACCESS FULL USER$ (cr=0 pr=0 pw=0 time=0 us cost=2 size=1584 card=88)
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
os thread startup 12 0.03 0.28
PX Deq: Join ACK 12 0.00 0.00
PX Deq: Parse Reply 12 0.03 0.06
reliable message 5 0.00 0.00
PX Deq: Execute Reply 90 0.33 1.18
PX Deq: Table Q Normal 3 0.00 0.00
PX Deq: Signal ACK RSG 1 0.00 0.00
enq: CR - block range reuse ckpt 3 0.01 0.03
log file sync 1 0.00 0.00
PX Deq: Signal ACK EXT 7 0.00 0.00
PX Deq: Slave Session Stats 8 0.00 0.00
SQL*Net message to client 1 0.00 0.00
SQL*Net message from client 1 7.71 7.71
create index leo6_index on leo6(object_id) parallel 4
Rows Row Source Operation
------- ---------------------------------------------------
3 PX COORDINATOR (cr=5 pr=0 pw=0 time=82 us)
0 PX SEND QC (ORDER) :TQ10001 (cr=0 pr=0 pw=0 time=0 us)
0 INDEX BUILD NON UNIQUE LEO6_INDEX (cr=0 pr=0 pw=0 time=0 us)(object id 0)
0 SORT CREATE INDEX (cr=0 pr=0 pw=0 time=0 us)
0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us cost=85 size=1189266 card=91482)
0 PX SEND RANGE :TQ10000 (cr=0 pr=0 pw=0 time=0 us cost=85 size=1189266 card=91482)
0 PX BLOCK ITERATOR (cr=0 pr=0 pw=0 time=0 us cost=85 size=1189266 card=91482)
0 TABLE ACCESS FULL LEO6 (cr=0 pr=0 pw=0 time=0 us cost=85 size=1189266 card=91482)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
reliable message 4 0.00 0.00
enq: KO - fast object checkpoint 1 0.01 0.01
PX Deq: Join ACK 1 0.00 0.00
PX Deq: Parse Reply 2 0.00 0.00
PX Deq: Execute Reply 58 0.16 0.50
PX Deq: Table Q qref 2 0.00 0.00
db file sequential read 4 0.00 0.00
enq: CR - block range reuse ckpt 2 0.09 0.14
log file sync 1 0.02 0.02
PX Deq: Signal ACK EXT 7 0.06 0.08
PX Deq: Slave Session Stats 3 0.00 0.00
alter index leo6_index rebuild parallel 4
Rows Row Source Operation
------- ---------------------------------------------------
3 PX COORDINATOR (cr=5 pr=0 pw=0 time=52 us)
0 PX SEND QC (ORDER) :TQ10001 (cr=0 pr=0 pw=0 time=0 us)
0 INDEX BUILD NON UNIQUE LEO6_INDEX (cr=0 pr=0 pw=0 time=0 us)(object id 0)
0 SORT CREATE INDEX (cr=0 pr=0 pw=0 time=0 us)
0 PX RECEIVE (cr=0 pr=0 pw=0 time=0 us)
0 PX SEND RANGE :TQ10000 (cr=0 pr=0 pw=0 time=0 us)
0 PX BLOCK ITERATOR (cr=0 pr=0 pw=0 time=0 us)
0 INDEX FAST FULL SCAN LEO6_INDEX (cr=0 pr=0 pw=0 time=0 us)(object id 74027)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
PX Deq: Join ACK 5 0.00 0.00
PX Deq: Parse Reply 4 0.00 0.00
PX Deq: Execute Reply 50 0.04 0.19
PX Deq: Table Q qref 3 0.00 0.00
db file sequential read 5 0.00 0.00
reliable message 3 0.00 0.00
enq: CR - block range reuse ckpt 3 0.01 0.02
PX Deq: Signal ACK EXT 4 0.03 0.03
PX Deq: Slave Session Stats 3 0.00 0.00
小结:上面的PX信息充分说明了我们在进行DDL操作时使用了并行技术
DML并行测试
前提:首先说明oracle对DML并行操作是有限制的,必须设置启用会话并行度,否则即使SQL指定了并行,oracle也不会执行DML并行操作
其次oracle只对partition table分区表做并行处理(有几个分区就开几个并行),普通表oracle不做并行处理(即使设置了并行度oracle也不做并行处理),只限delete update merge操作
我们做个insert并行测试吧
在insert测试中只有insert into ...... select ......做并行才有意义,insert into ......values ......单条插入没有意义
LEO1@LEO1> explain plan for insert /*+ parallel(leo5 4) */ into leo5 select /*+ parallel(leo6 2) */ * from leo6;
Explained. 这种写法只生成执行计划不做实际插入操作,下面我们来看看执行计划情况
LEO1@LEO1> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 987566897
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 60249 | 11M| 170 (1)| 00:00:03 | | | |
| 1 | LOAD TABLE CONVENTIONAL | LEO5 | | | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10000 | 60249 | 11M| 170 (1)| 00:00:03 | Q1,00 | P->S | QC (RAND) |
| 4 | PX BLOCK ITERATOR | | 60249 | 11M| 170 (1)| 00:00:03 | Q1,00 | PCWC | |
| 5 | TABLE ACCESS FULL | LEO6 | 60249 | 11M| 170 (1)| 00:00:03 | Q1,00 | PCWP | |
------------------------------------------------------------------------------------------------------------------
小结:执行计划 insert和select操作别分使用了并行,它们是相互独立的互不干涉
并行 执行计划 PARALLEL_DEGREE_POLICY 10391 V$PQ_TQSTAT DDL DML
http://www.itpub.net/thread-1760486-1-1.html
http://www.itpub.net/thread-1760488-1-1.html