大家好,我是 JiekeXu,江湖人称“强哥”,荣获 Oracle ACE Pro 称号,墨天轮 MVP,墨天轮年度“墨力之星”,拥有 Oracle OCP/OCM 认证,MySQL 5.7/8.0 OCP 认证以及 PCA、PCTA、OBCA、OGCA、KCP 等众多国产数据库认证证书,今天和大家一起来看看八千字带你了解 Oracle 并行那些事(二),欢迎点击最上方蓝字“JiekeXu DBA之路”关注我的微信公众号,然后点击右上方三个点“设为星标”置顶,更多干货文章才能第一时间推送,谢谢!
目 录
一)并行执行的工作原理
SQL 语句的并行执行过程
生产者/消费者模型
并行粒度
生产者和消费者之间的分配方式
并行执行服务器如何通信
二)并行的相关概念
并行执行相关视图
并行 DML 的限制
三)并行查询
四)并行 DML
默认并行度
LOB 列的并行
五)并行创建表
六)并行创建索引
七)并行收集统计信息
八)rman 备份的并行
九)23ai 并行新特性
三)并行查询
在书写 SQL 语句时我们仅需在 select 关键字后面添加一个 HINT /*+ parallel(n) */ 即可,而不需要在所有的查询下都加 HINT,这一点以前我也是不知道的,看了老虎刘的文章才明白,很多一部分 DBA 包括专家在内都在沿用 10g 的写法,但是 11g 以上已经变的更简单了,不用在考虑后面的多表关联,子查询等怎么添加多个 HINT,记住只需要在第一个 select 后面添加就好。
Select /*+ parallel(8) */ count(*) from emp;
SELECT /*+ PARALLEL(8) */ customers.cust_first_name, customers.cust_last_name,
MAX(QUANTITY_SOLD), AVG(QUANTITY_SOLD)
FROM sales, customers
WHERE sales.cust_id=customers.cust_id
GROUP BY customers.cust_first_name, customers.cust_last_name;
索引组织表支持多种并行扫描方法。
非分区索引组织表的并行快速全扫描 分区索引组织表的并行快速全扫描 分区索引组织表的并行索引范围扫描
对于有溢出区的索引组织表和包含 LOB 的索引组织表,可以使用这些扫描方法。
非分区索引组织表
对非分区索引组织表的并行查询使用并行快速全扫描。工作分配的方式是将索引段划分为足够多的块范围,然后以需求驱动的方式将块范围分配给并行执行服务器。与任何行对应的溢出块只能由拥有该行的进程以需求驱动的方式访问。
分区索引组织表
索引范围扫描和快速全扫描都可以并行执行。对于并行快速全扫描,并行化方法与非分区索引组织表相同。根据 DOP 的不同,每个并行执行服务器会得到一个或多个分区,每个分区都包含主键索引段和相关溢出段(如果有)。
SQL 查询只能在特定条件下并行执行。只有满足以下条件之一,SELECT 语句才能并行执行:
查询包含语句级或对象级并行提示规范(PARALLEL 或 PARALLEL_INDEX)。
查询中引用的模式对象有与之相关的 PARALLEL 声明。
自动并行程度(Auto DOP)已启用。
使用 ALTER SESSION FORCE PARALLEL QUERY 语句强制执行并行查询。
全表扫描 A full table scan
跨越多个分区的索引范围扫描 An index range scan spanning multiple partitions
索引快速全扫描 An index fast full scan
并行表函数 A parallel table function
四)并行 DML
一般情况下,我们都只是在会话级别开启并行 DML。那么 DML 有 INSERT、DELETE、UPDATE、MERGE 这四种,例如下面这样开启并行 DML:
alter session enable parallel dml;
--后面的并行写不写都可以
INSERT /*+ parallel(16) */ into emp1 select /*+ parallel(16) */ from emp where empno=30;
当然也有的直接是 alter session force parallel dml parallel 8; 这样就算后面的 SQL 语句没有加 HINT 也是使用并行 DML。
在 Oracle 12c 以后的版本中,上面语句得到进一步简化,直接一条语句添加 HINT /*+ enable_parallel_dml parallel(8) */ 开启 PDML。
delete /*+ enable_parallel_dml parallel(8) */ from ds.mg_d_busi_detail where datadate < sysdate -1;
--如下并行没有起作用,因为前面和后面的并行度不一致
SQL> explain plan for INSERT /*+ enable_parallel_dml parallel(16) */ into emp1 select /*+ parallel(8) */ EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO from emp a,dept b where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3956160932
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 4 | 152 | 3 (0)| 00:00:01 |
| 1 | LOAD TABLE CONVENTIONAL | EMP1 | | | | |
|* 2 | TABLE ACCESS FULL | EMP | 4 | 152 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A"."DEPTNO">=30)
Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 2 (U - Unused (2))
---------------------------------------------------------------------------
0 - STATEMENT
U - parallel(16) / hint conflicts with another in sibling query block
U - parallel(8) / hint conflicts with another in sibling query block
Note
-----
- PDML disabled because object is not decorated with parallel clause
- Direct Load disabled because no append hint given and not executing in parallel
27 rows selected.
并行 DML 12c 新特性
New 12c Hint: ENABLE_PARALLEL_DML Lets you Easily Enable Parallel DML (PDML) at the Statement Level (Doc ID 1991034.1)
SQL> explain plan for INSERT /*+ enable_parallel_dml parallel(16) */ into emp1 select EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO from emp a,dept b where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4200853112
----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | 4 | 152 | 2 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | 4 | 152 | 2 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 3 | LOAD AS SELECT (HYBRID TSM/HWMB)| EMP1 | | | | | Q1,00 | PCWP | |
| 4 | OPTIMIZER STATISTICS GATHERING | | 4 | 152 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
| 5 | PX BLOCK ITERATOR | | 4 | 152 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
|* 6 | TABLE ACCESS FULL | EMP | 4 | 152 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - filter("A"."DEPTNO">=30)
Note
-----
- Degree of Parallelism is 16 because of hint
22 rows selected.
故如下三种 SQL 均等价,并行度为 16
(1)12c 以上使用 Hint 开启并行
INSERT /*+ enable_parallel_dml parallel(16) */ into emp1
select EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO
from emp a,dept b
where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
(2)11g 以上会话级别开启并行 dml
alter session enable parallel dml;
INSERT /*+ parallel(16) */ into emp1
select EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO
from emp a,dept b
where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
(3)10g 相关版本需要对每个表单独设置并行
alter session enable parallel dml;
INSERT /*+ parallel( emp1 16) */ into emp1
select /*+ parallel(emp 16) parallel(dept 16) */ EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO
from emp a,dept b
where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
示例如下:
SQL> conn scott/scott
Connected.
set line 130 pages 234
alter session enable parallel dml;
explain plan for INSERT /*+ parallel( emp1 16) */ into emp1 select /*+ parallel(emp 16) parallel(dept 16) */ EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO from emp a,dept b where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
select * from table(dbms_xplan.display);
注意,如果是 11g 及以上的数据库,只要在整个 SQL 的任何一个关键字(select、update、insert、delete、merge)后面出现一次parallel(n),那么整个SQL相关的表,都会使用并行,如果是 10g 的库还需要分别指定每个要并行的表才行,/*+ parallel(emp 8) parallel(dept 8) */。如果写错并行 HINT,有可能会使用自动并行,这可能会导致系统资源 IO 标高,进而影响其他操作无法高效运行导致性能问题。
默认并行度
如果指定了并行,但未列出并行度(DOP),则对象将获取默认DOP。
ALTER TABLE sales PARALLEL;
默认并行度使用公式根据系统配置确定 DOP,如下所示:
l对于单个实例,DOP =PARALLEL_THREADS_PER_CPU x CPU_COUNT
l对于 Oracle RAC 配置,DOP =PARALLEL_THREADS_PER_CPU x sum(CPU_COUNT)
默认情况下,sum(CPU_COUNT) 是集群中的 CPU 总数。但是,如果您使用 Oracle RAC 服务来限制可以执行并行操作的节点数,则 sum(CPU_COUNT) 是属于该服务的节点之间的 CPU 总数。例如,在 4 节点 Oracle RAC 集群上,每个节点有 8 个 CPU 核心且没有 Oracle RAC 服务,则默认 DOP 为 2 x (8+8+8+8) = 64。
另外,还有自动并行度 (Auto DOP) 使 Oracle 数据库能够自动决定语句是否应并行执行以及应使用什么 DOP。如下图所示,因没有写具体并行度,则是自动并行 Auto DOP,该自动并行由PARALLEL_THREADS_PER_CPU * sum(CPU_COUNT) 决定。
不过,优化器会限制实际最大 DOP,以确保并行执行服务器不会压垮系统。该限制由参数 PARALLEL_DEGREE_LIMIT 设置。该参数的默认值为 CPU,这意味着 DOP 受系统 CPU 数量(PARALLEL_THREADS_PER_CPU * sum(CPU_COUNT))的限制,也称为默认 DOP。默认 DOP 可确保单个用户操作不会压垮系统。通过调整该参数设置,可以控制优化程序为 SQL 语句选择的最大 DOP。如果 Oracle 数据库资源管理器用于限制 DOP,优化器还可以进一步限制可选择的最大 DOP。
如果启用了并行 DML,并且在数据字典中为表设置了 PARALLEL 提示或 PARALLEL 属性,那么插入操作就是并行和附加的,除非有限制。如果缺少 PARALLEL 提示或 PARALLEL 属性,插入操作将以串行方式执行。自动 DOP 仅在并行 DML 启用或强制的情况下并行 SQL 语句的 DML 部分。如果启用了并行 DML,则可以使用 NOAPPEND 提示来执行并行常规插入操作。例如,可以在 SQL INSERT 语句中使用 /*+ noappend parallel */ 来执行并行常规插入操作。
SQL> INSERT /*+ NOAPPEND PARALLEL */ INTO sales_hist SELECT * FROM sales;
并行常规插入操作的优点是可以执行在线操作,不受直接路径 INSERT 的限制。并行常规插入操作的缺点是,这个过程可能比直接路径 INSERT 慢。
LOB 列的并行
对带有 SecureFiles LOB 列的普通表可以进行并行查询,不能进行并行 DML。
create table t (a number,b varchar2(200),c clob) lob(c) store as securefile;
insert into t values(1,'aaaa','xxxxxxxxxx');
insert into t values(2,'bbbb','yyyyyyyyyy');
insert into t values(3,'cccc','zzzzzzzzzz');
commit;
explain plan for insert /*+ parallel enable_parallel_dml */ into t select /*+ parallel */ * from t;
select * from table(dbms_xplan.display(format=>'basic +note'));
explain plan for delete /*+ parallel enable_parallel_dml */ from t;
select * from table(dbms_xplan.display(format=>'basic +note'));
------------------------------------------
| Id | Operation | Name |
------------------------------------------
| 0 | DELETE STATEMENT | |
| 1 | DELETE | T |
| 2 | PX COORDINATOR | |
| 3 | PX SEND QC (RANDOM)| :TQ10000 |
| 4 | PX BLOCK ITERATOR | |
| 5 | TABLE ACCESS FULL| T |
------------------------------------------
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- automatic DOP: Computed Degree of Parallelism is 2
- PDML disabled because single fragment or non partitioned table used
对带有 SecureFiles LOB 列的分区表可以进行并行 DML 操作,但有效的并行仅是分区的数量,因为在这种情况下,将分区用作 PX 粒度。我们可以通过视图 V$PQ_SESSTAT 查看。
create table t_par (a number,b varchar2(200),c clob) lob(c) store as securefile partition by hash(a) partitions 4;
explain plan for delete /*+ parallel(8) enable_parallel_dml */ from t_par;
select * from table(dbms_xplan.display(format=>'basic +note'));
select * from V$PQ_SESSTAT;
五)并行创建表
如下创建表,使用并行后,需要及时取消并行。
create table scott.test151 parallel 16
as select EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO
from scott.emp a,scott.dept b
where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 234 | 2 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM)| :TQ10000 | 6 | 234 | 2 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | 6 | 234 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
| 4 | TABLE ACCESS FULL| TEST151 | 6 | 234 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
--------------------------------------------------------------------------------------------------------------
Note
-----
- Degree of Parallelism is 4 because of table property
alter table scott.test151 noparallel;
ALTER TABLE sales PARALLEL 8; --手动设置并行
Set autot on
select * from scott.test151;
--------------------------------------------------------------------------------------------------------------
|Id| Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------
|0| SELECT STATEMENT | | 5 | 435 | 2 (0)| 00:00:01 | | | |
|1| PX COORDINATOR | | | | | | | | |
|2| PX SEND QC (RANDOM)| :TQ10000 | 5 | 435 | 2 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
|3| PX BLOCK ITERATOR | | 5 | 435 | 2 (0)| 00:00:01 | Q1,00 | PCWC | |
|4| TABLE ACCESS FULL| TEST151 | 5 | 435 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
--------------------------------------------------------------------------------------------------------------
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
- Degree of Parallelism is 16 because of table property
如下 CTAS 使用并行,然后继续使用并行 DML。
create table scott.test151 parallel(degree 16) as select /*+ parallel(16) */ EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO from scott.emp a,scott.dept b where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
INSERT /*+ parallel(16) */ into emp1 select EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,a.DEPTNO from emp a,dept b
where a.DEPTNO=b.DEPTNO and a.DEPTNO>=30;
alter table scott.test151 noparallel; --及时取消并行
这种情况需要特别注意,创建的表默认并行度就是 16,需要手工修改回 1 或者取消并行,这一步非常重要,一定要做:
六)并行创建索引
CREATEINDEX、ALTER INDEX REBUILD 均可使用并行创建/重建索引。并行 DDL 不能在有对象列的表上执行。并行 DDL 不能发生在具有 LOB 列的非分区表上。
create index idx_emp1_deptno on emp1(deptno) parallel 4 online;
alter index idx_emp1_deptno noparallel;
七)并行收集统计信息
关于统计信息去年 12 月份已经写过一篇很详细的内容,并输出了脑图,感兴趣的可以去看看。并行收集统计信息可以使用DEGREE并行执行,但同一个表的分区之间还是串行执行,使用CONCURRENT并发收集,分区之间可以并行收,DEGREE和CONCURRENT同时使用。
单个对象的并行统计信息收集 通过 GATHER_*_STATS 参数 DEGREE控制 假设EMP1表的degree定义为4, 那么收集统计信息时候有4个进程运行。
exec dbms_stats.gather_table_stats('SCOTT','EMP1',degree=>4);
单个对象并行统计信息收集的限制
Exec DBMS_STATS.GATHER_TABLE_STATS(null,‘SALES');
单个分区可以并行收集,收集完一个分区,再收集下一个,多个分区不能同时收集,对于分区表首次采集时间可能比较长。
同一时间收集多个对象统计信息,通过 DBMS_STATS 的 CONCURRENT 属性控制(MANUAL、AUTOMATIC、ALL、OFF默认),使用 Scheduler 和高级队列调度,并发进程数由参数 job_queue_processes 决定,每个正在运行的任务仍然可以是并行的。
ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'DEFAULT_PLAN';
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=8;
EXEC DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','ALL');
SELECT DBMS_STATS.GET_PREFS('CONCURRENT') FROM DUAL;
EXEC DBMS_STATS.GATHER_SCHEMA_STATS('SH');
--关闭并发
EXEC DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','OFF');
--查看并发收集进度
SET LINESIZE 1000
COLUMN TARGET FORMAT a8
COLUMN TARGET_TYPE FORMAT a25
COLUMN JOB_NAME FORMAT a14
COLUMN START_TIME FORMAT a40
SELECT TARGET, TARGET_TYPE, JOB_NAME,
TO_CHAR(START_TIME, 'dd-mon-yyyy hh24:mi:ss')
FROM DBA_OPTSTAT_OPERATION_TASKS
WHERE STATUS = 'IN PROGRESS'
AND OPID = (SELECT MAX(ID)
FROM DBA_OPTSTAT_OPERATIONS
WHERE OPERATION = 'gather_schema_stats');
官方链接:https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/gathering-optimizer-statistics.html#GUID-3D36585C-5850-402E-9DB5-2EE9AAAD8C36
八)Rman 备份的并行
如下通过分配通道,则可以实现并行。
run {
allocate channel c1 type disk ;
allocate channel c2 type disk ;
allocate channel c3 type disk ;
allocate channel c4 type disk ;
backup as compressed backupset datafile 7,8,9 format '/backup/%d_%I_%s_%p.bak';
--backup as compressed backupset database format '/backup/%d_%I_%s_%p.bak';
release channel c1;
release channel c2;
release channel c3;
release channel c4;
}
查看备份进度
Select inst_id,username,opname,target,sofar,totalwork*100/totalwork
from gv$session_longops where sofar < totalwork;
九)23ai 并行新特性
在 Oracle 23ai 之前的版本中,开启了 DML 的并行后,接下来的 DML 语句将会产生一个表锁,在 commit 之前,当前 session 不能对该表做查询和 dml 操作,其他 session 也不能对该表做 DML 操作,否则会报错 ORA-12838。
alter session enable parallel dml;
create table scott.jiekexu as select * from dba_objects ;
insert /*+ append parallel(t0,16) */ into scott.jiekexu select * from scott.jiekexu t1;
Select count(*) from scott.jiekexu;
ORA-12838: cannot read/modify an object after modifying it in parallel
当然,这个问题在 Oracle 23ai 版本出来之前一直都存在,直到今年发布的 Oracle 23ai 版本才解决了这个问题。如下所示,并行之后可以继续其他的 DML 语句,无 ORA-12838 报错。
十)参考链接
https://www.alfredzhao.cn/index.php/2021/01/08/i-love-parallel/
https://blogs.oracle.com/datawarehousing/post/parallel-dml-on-tables-with-lob-columns
https://docs.oracle.com/en/database/oracle/oracle-database/23/admin/managing-processes.html#GUID-B3798D1E-E259-4EDB-815E-8ED36205A5B5
https://docs.oracle.com/en/database/oracle/oracle-database/23/vldbg/using-parallel.html#GUID-68ED8F5E-DD97-4762-985C-4C3AF85F9629
https://docs.oracle.com/en/database/oracle/oracle-database/19/vldbg/types-parallelism.html#GUID-6626C70C-876C-47A4-8C01-9B66574062D8
https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/gathering-optimizer-statistics.html#GUID-3D36585C-5850-402E-9DB5-2EE9AAAD8C36
https://www.modb.pro/course/article/110?lsId=5346&catalogId=4
--你可能还想看:
--陈焕生:深入理解Oracle 的并行执行(一)到(五)
http://www.uml.org.cn/sjjm/2015030210.asp
http://www.uml.org.cn/sjjm/2015030310.asp
http://www.uml.org.cn/sjjm/2015030411.asp
http://www.uml.org.cn/sjjm/2015030511.asp
http://www.uml.org.cn/sjjm/2015030610.asp
分享几个数据库备份脚本
一文搞懂 Oracle 统计信息
我的 Oracle ACE 心路历程
MOP 系列|MOP 三种主流数据库索引简介
Oracle 主流版本不同架构下的静默安装指南
关机重启导致 ASM 磁盘丢失数据库无法启动
Oracle SQL 性能分析(SPA)原理与实战演练
Oracle 11g 升级到 19c 需要关注的几个问题
Windows 10 环境下 MySQL 8.0.33 安装指南
SQL 大全(四)|数据库迁移升级时常用 SQL 语句
OGG|使用 OGG19c 迁移 Oracle11g 到 19C(第二版)
Oracle 大数据量导出工具——sqluldr2 的安装与使用
Oracle ACE 视角下的国产数据库现状与选型及应对策略
从国产数据库调研报告中你都能了解哪些信息及我的总结建议
使用数据泵利用 rowid 分片导出导入 lob 大表及最佳实践
在归档模式下直接 rm dbf 数据文件并重启数据库还有救吗?
——————————————————————————
公众号:JiekeXu DBA之路
墨天轮:https://www.modb.pro/u/4347
CSDN :https://blog.csdn.net/JiekeXu
ITPUB:https://blog.itpub.net/69968215
腾讯云:https://cloud.tencent.com/developer/user/5645107——————————————————————————