33-Oracle Parallel 并行处理的选择和实践
小伙伴们是不是偶尔会遇见超大的表,几百万、上千万行的数据,查询或是导出各种卡顿,服务器现在都是十核上百核心了,内存也轻轻松松到几十g上百g了。如果使用并行来用好机器的实力,跑起来,快起来。使用并行查询将执行时间大大缩短,在什么场景上可以使用呢,有啥要规避的。
一、Parallel并行
1. 技术本质
通过任务分解-并行执行-结果合并流程(QC进程+PX Slaves架构),将单进程任务拆分为多进程并发处理,实现近乎线性的性能扩展
2. 适用场景
类型 | 举例 | 性能提升依据 | |
OLAP查询 | 亿级表全表扫描、多表JOIN | 并行扫描使多线程查询耗时降至串行 | |
批量DML | 千万级数据UPDATE/INSERT | PDML通过并行写入减少事务提交次数 | |
对象维护 | 大表在线重定义、索引创建 | 并行建索引速度提升 | |
数据迁移 | Data Pump导出TB级数据 | PARALLEL参数加速RAC集群资源利用 |
规避的场景:
高频OLTP事务(行级锁冲突)、含触发器依赖操作、资源受限(CPU/I/O 瓶颈)系统开了会更卡。
二、实践脚本
1. 创建测试表(千万行数据)真实的医疗和工业生产,大量的这样的表。
ALTER SESSION ENABLE PARALLEL DML;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 32;
ALTER TABLE target_table NOLOGGING; -- 减少Redo日志
ALTER INDEX idx_parallel REBUILD PARALLEL 32; -- 完成后并行重建索引-- 创建大表(2千万行)19c环境,sql中的connect by功能太香了速度快,
--然而1亿条的时候直接ORA-300009,32C/128G,SGA=64G
-- 启用并行 DML 并设置并行度(推荐 DOP = CPU 核心数 × 0.75)
ALTER SESSION ENABLE PARALLEL DML;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 24;
ALTER SESSION FORCE PARALLEL DDL PARALLEL 24;-- 创建表(NOLOGGING + PARALLEL + 直接路径插入)
CREATE TABLE sales_data
PARALLEL 32
NOLOGGING
AS
SELECT /*+ APPEND PARALLEL(24) */ROWNUM AS id,TRUNC(DBMS_RANDOM.VALUE(1,1000)) AS product_id,TRUNC(SYSDATE - DBMS_RANDOM.VALUE(1,3650)) AS sale_date,ROUND(DBMS_RANDOM.VALUE(10,5000), 2) AS amount
FROM DUAL
CONNECT BY LEVEL <= 20000000;-- 恢复表属性(避免后续操作继承并行设置)
ALTER TABLE sales_data NOPARALLEL;
ALTER TABLE sales_data LOGGING;
--
----实际运行
[oracle@test19:/home/oracle]# sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on 星期六 6月 14 14:29:23 2025
Version 19.3.0.0.0Copyright (c) 1982, 2019, Oracle. All rights reserved.
连接到:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0SYS@test19> show pdbs;CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------2 PDB$SEED READ ONLY NO3 PDBRS6 READ WRITE NO
SYS@test19> alter session set container=PDBRS6;
----
创建时候机器负载
2. 场景1聚合统计:并行查询 vs 串行查询
--比较执行时间,十几倍的提升
-- 串行查询(全表扫描)
SET TIMING ON
SELECT /*+ NO_PARALLEL */ product_id, SUM(amount)
FROM sales_data
GROUP BY product_id;
-- 执行时间:已用时间: 00: 00: 02.98-- 并行查询(DOP=8)
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 8;
SELECT /*+ PARALLEL(sales_data, 8) */ product_id, SUM(amount)
FROM sales_data
GROUP BY product_id;
-- 执行时间:已用时间: 00: 00: 00.45
3. 场景2批量更新:并行DML vs 串行DML
-- 串行更新
UPDATE /*+ NO_PARALLEL */ sales_data
SET amount = amount * 1.1
WHERE product_id BETWEEN 100 AND 200;
--已更新 2022843 行。
--已用时间: 00: 01: 46.64-- 并行DML(需显式启用)
ALTER SESSION ENABLE PARALLEL DML;UPDATE /*+ PARALLEL(sales_data, 8) */ sales_data
SET amount = amount * 1.1
WHERE product_id BETWEEN 100 AND 200;
COMMIT; -- 必须提交释放资源
已更新 2022843 行。
已用时间: 00: 00: 17.97
COMMIT
提交完成。
已用时间: 00: 00: 00.11
4. 场景3索引创建:并行DDL
-- 串行创建索引
CREATE INDEX idx_serial ON sales_data(product_id);
-- 索引已创建。
--已用时间: 00: 00: 25.31
-- 并行创建索引(DOP=12)
SYS@test19> DROP INDEX idx_serial;
索引已删除。
已用时间: 00: 00: 00.17
CREATE INDEX idx_parallel ON sales_data(product_id) PARALLEL 12;
SYS@test19> CREATE INDEX idx_parallel ON sales_data(product_id) PARALLEL 12;
索引已创建。
-- 已用时间: 00: 00: 02.37
-- 关闭并行属性
ALTER INDEX idx_parallel NOPARALLEL;
索引已更改。
已用时间: 00: 00: 00.02
三、最佳实践与避坑指南
1. 并行度计算公式
DOP=(CPU Cores×parallel threads perc pu)×0.75−−预留25%
-- 查看系统参数
SHOW PARAMETER cpu_count; -- CPU核心数
SYS@test19> SHOW PARAMETER cpu_count;
NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
cpu_count integer 32SHOW PARAMETER parallel_threads_per_cpu; --虚拟CPU
SYS@test19> SHOW PARAMETER parallel_threads_per_cpu
NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
parallel_threads_per_cpu integer 1
2. 对应配置
-- 限制全局并行进程数(防资源耗尽)
ALTER SYSTEM SET parallel_max_servers = 64;
-- 启用自适应并行(Oracle 11g+)
ALTER SESSION SET parallel_degree_policy = AUTO;
SYS@test19> ALTER SYSTEM SET parallel_max_servers = 64;
系统已更改。
已用时间: 00: 00: 00.01
SYS@test19> ALTER SESSION SET parallel_degree_policy = AUTO;
会话已更改。
已用时间: 00: 00: 00.00
4. 常见问题
- 1:并行更新后查询报错 ORA-12838原因:未提交事务导致后续会话无法读取被修改的表。解决:执行 COMMIT 后重试。
- 2:并行DDL引发 ORA-00600 错误原因:parallel_execution_message_size 参数过小。
ALTER SYSTEM SET parallel_execution_message_size=8192 SCOPE=SPFILE;
SHUTDOWN IMMEDIATE;
STARTUP;
--
SYS@test19> show parameter parallel_execution_message_size;NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
parallel_execution_message_size integer 16384
3:生效验证步骤,并行查询:
-- 生成执行计划(不实际执行SQL)
EXPLAIN PLAN FOR
SELECT /*+ PARALLEL(sales_data, 8) */ product_id, SUM(amount)
FROM sales_data
GROUP BY product_id;
-- 检查执行计划中的并行标识
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(FORMAT=>'ALL'));
SYS@test19> show parameter parallel_execution_message_size;NAME TYPE VALUE
------------------------------------ --------------------------------- ------------------------------
parallel_execution_message_size integer 16384
EXPLAIN PLAN FOR
SELECT /*+ PARALLEL(sales_data, 8) */product_id, SUM(amount)
FROM sales_data5 GROUP BY product_id;已解释。已用时间: 00: 00: 00.04
SYS@test19> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(FORMAT=>'ALL'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3011834688--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20M| 503M| 3005 (4)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | 20M| 503M| 3005 (4)| 00:00:01 | Q1,01 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | 20M| 503M| 3005 (4)| 00:00:01 | Q1,01 | PCWP | |
| 4 | PX RECEIVE | | 20M| 503M| 3005 (4)| 00:00:01 | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | 20M| 503M| 3005 (4)| 00:00:01 | Q1,00 | P->P | HASH |
| 6 | HASH GROUP BY | | 20M| 503M| 3005 (4)| 00:00:01 | Q1,00 | PCWP | |
| 7 | PX BLOCK ITERATOR | | 20M| 503M| 2914 (1)| 00:00:01 | Q1,00 | PCWC | |
| 8 | TABLE ACCESS FULL| SALES_DATA | 20M| 503M| 2914 (1)| 00:00:01 | Q1,00 | PCWP | |
--------------------------------------------------------------------------------------------------------------------Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------1 - SEL$18 - SEL$1 / SALES_DATA@SEL$1Column Projection Information (identified by operation id):
-----------------------------------------------------------1 - "PRODUCT_ID"[NUMBER,22], SUM()[22]2 - (#keys=0) "PRODUCT_ID"[NUMBER,22], SUM()[22]3 - (#keys=1; rowset=256) "PRODUCT_ID"[NUMBER,22], SUM()[22]4 - (rowset=256) "PRODUCT_ID"[NUMBER,22], SYS_OP_MSR()[25]5 - (#keys=1) "PRODUCT_ID"[NUMBER,22], SYS_OP_MSR()[25]6 - (#keys=1; rowset=256) "PRODUCT_ID"[NUMBER,22], SYS_OP_MSR()[25]7 - (rowset=256) "PRODUCT_ID"[NUMBER,22], "AMOUNT"[NUMBER,22]8 - (rowset=256) "PRODUCT_ID"[NUMBER,22], "AMOUNT"[NUMBER,22]Hint Report (identified by operation id / Query Block Name / Object Alias):
Total hints for statement: 1
---------------------------------------------------------------------------8 - SEL$1 / SALES_DATA@SEL$1- PARALLEL(sales_data, 8)Note
------ dynamic statistics used: dynamic sampling (level=4)- Degree of Parallelism is 8 because of hint已选择 45 行。已用时间: 00: 00: 00.24
“数据量越大,并行收益越高;资源越充足,加速比越接近线性”,
同时这是一把双刃剑,避免滥用并行!优先通过索引优化、SQL 调优解决性能问题。
仅在硬件资源充足且数据量巨大时启用并行,否则可能拖垮系统