OceanBase
  • 产品
  • 解决方案
  • 客户
  • 合作伙伴
  • 资源与服务
  • 文档
  • 社区
云控制台登录 / 注册
  • 免费试用
本地部署
OceanBase 分布式数据库

首批通过分布式安全可靠测评,为关键业务系统打造

OceanBase 集中式数据库

集中式架构,兼具性能与成本优势的集中式数据库

OceanBase 社区版

兼容 MySQL 的单机分布式一体化开源数据库

OceanBase seekdb

为现代 AI 应用打造的开源混合搜索数据库

云上部署
OB Cloud

一体化云数据库,打造面向多云的一致性体验

一体机
OceanBase 数据库一体机

软硬一体,提供极致性能与高可靠性保障

OceanBase AI 一体机

基于 OceanBase AI Stack 的智能一体机

工具
迁移评估工具(OMA)
数据迁移工具(OMS)
开发者工具(ODC)
运维管理工具(OCP)
自治服务工具(OAS)
一体化关键能力
TP 事务处理

面向关键业务负载的事务处理能力,保障大规模业务稳定运行与数据零丢失

AP 实时分析

原生支持事务与分析融合,低延迟洞察业务数据,驱动智能决策与敏捷运营

AI 现代负载

湖库一体管理多模态数据离在线处理,AI 原生支撑 Agent 规模化应用

oceanbase白皮书

OceanBase 一体化分布式数据库

通用场景
全场景业务系统 OLTP
实时分析混合负载
异地多活
多基础设施部署
一站式传统数据库升级
混合云部署
一库多芯软硬件混合部署
分布式数据库单机部署
大存储类数据库降本
冷数据归档降本
多实例资源整合
分库分表一体化升级
高并发场景
数据中台
行业解决方案
国有大行和股份制银行核心系统解决方案
区域性银行核心系统解决方案
寿险核心系统解决方案
产险核心系统解决方案
资管交易类系统解决方案
资管 TA 清算类系统解决方案
运营商核心系统解决方案
人社核心系统解决方案
电力核心系统解决方案
行业专区
银行专区

助力银行完成各类核心业务系统升级

保险专区

寿险、产险核心系统升级的更佳选择

零售专区

助力200+零售行业客户规模化落地

DB 大咖说
oceanbase爱奇艺

百亿级卡券业务的“单库双擎”架构升级

oceanbase四川银行

800个测试用例选定分布式数据库

oceanbase太平洋保险

先难后易,核心系统数据库升级复盘

行业案例
oceanbase交通银行

核心数据库的“分布式革命”

oceanbase中国移动

B域核心CRM&BOSS近乎零改造分布式升级

oceanbase理想

打造领先的智能制造系统和自动驾驶体验

演讲实录
oceanbase中国联通

集团应用分布式数据库覆盖B/O/M域

oceanbase国泰海通

智能推送系统稳定支撑单日亿级消息处理量

oceanbase中国联合航空

中国首款机票盲盒背后的数据库力量

用户实践
oceanbase北京银行

最快速度完成40余套系统国产数据库升级

oceanbase维沃移动通信有限公司

替换 MySQL 分库分表,探索成本效益最优

oceanbase滴滴

数据库大规模运维体系建设及落地实践

合作伙伴
合作伙伴类型
联合解决方案
产业生态伙伴
经销商伙伴
技术服务伙伴
培训认证伙伴
生态联合解决方案
神州信息 x OceanBase 银行核心系统
长亮科技 x OceanBase 新核心系统
中电金信 x OceanBase 金融分布式核心系统
天阳科技 x OceanBase 贷记卡方案
易诚互动 x OceanBase 手机银行方案
恒生 x OceanBase UF3.0/O45/TA/估值方案
商业发行版
云树®数据库软件 ActionDB
服务
支持与服务
提交工单
软件下载
OceanBase 企业版
OceanBase 社区版
OB Cloud
学习
培训与认证
在线课堂
在线体验
开发者
开发者中心
资料
行业报告与白皮书
官方博客
年度发布会资料
开发者大会资料
oceanbase白皮书

金融核心系统数据库升级路径与场景实践

oceanbase白皮书

人社关键业务数据库一体化升级实践

产品文档
oceanbaseOceanBase 数据库
驱动和中间件
oceanbaseOB Cloud 云数据库
工具与组件
oceanbaseOceanBase 数据库一体机
生态商业产品
快速上手
OceanBase 数据库
OB Cloud 云数据库
知识库
汇聚常见产品使用问题案例
在线体验

Demo与实验,感受 OceanBase 的核心能力与应用场景

OceanBase 最佳实践
了解 OceanBase 分布式数据库的架构与系统原理
技术博客

技术解析 | 用户实践 | 社区月报

在线课堂

电子书 |视频课程|在线培训

Developer Hub
应用开发Demo | 数据开发与集成工具
问答论坛

快速答疑 | 常见问题 | 技术交流

社区活动

Meetup | 技术公开课

GitHub

查看源码 | 贡献代码 | 建议反馈

加入社区

社区组织 | 社区用户贡献 |开发者贡献

进入社区首页
oceanbase数据库大赛

第五届OceanBase数据库大赛

oceanbase免费课程
从故障处理到性能调优:OceanBase资深DBA进阶培训
切换语言
  • 中文站 - 简体中文
  • International - English
  • 日本站 - 日本語
文档反馈
  1. 文档中心
  2. OceanBase 数据库
  3. 分布式版
  4. V4.3.5
  5. 参考指南
  6. 性能调优
  7. SQL 调优指南
  8. 分布式执行计划
  9. 并行 DML
分布式版-V4.3.5LTS
  • V4.3.5 文档更新记录
  • What's New
  • 简介
  • 快速上手
  • 应用开发
  • 部署
  • 升级
  • 数据迁移
  • 管理数据库
  • AP
  • 向量搜索
  • 共享存储
  • 生态集成
  • 实践教程
  • 参考指南
    • 系统原理
    • 系统管理
    • 数据库对象管理
    • 数据库设计规范和约束
    • SQL 参考
    • PL 参考
    • 系统视图
    • 配置项和系统变量
    • 错误码
    • 性能调优
      • 概述
      • 性能相关工具
      • 系统调优
      • 业务模型调优
      • 性能诊断
      • SQL 调优指南
        • SQL 请求执行流程
        • SQL 执行计划
        • 分布式执行计划
          • 分布式执行和并行查询
          • 分布式计划的生成
          • 分布式执行计划调度
          • 分布式执行计划管理
          • 并行执行配置方式及优先级规则
          • 自动并行度 Auto DOP
          • 并行查询
          • 并行查询的参数调优
          • 并行 DML
          • 并行 DDL
        • 并行执行计划
        • SQL 优化
        • 相关术语
        • SQL 调优常见问题
        • SQL 执行计划调优实践
        • SQL 性能分析实践
    • 性能测试
    • 数据库代理
    • 驱动
    • 平台产品
    • 组件 & 工具
    • 数据库插件
  • 常见问题
  • 版本发布记录
  • 术语
  1. 文档中心
  2. OceanBase 数据库
  3. 分布式版
  4. V4.3.5
  5. 参考指南
  6. 性能调优
  7. SQL 调优指南
  8. 分布式执行计划
  9. 并行 DML

并行 DML

更新时间:2026-04-07 20:57:20

github-fill编辑
编组分享

并行 DML 通过使用并行执行机制来提高对大型数据库的表和索引执行插入、更新、删除等操作,以提高执行效率。对于决策支持系统 (DSS)的数据库,并行 DML 提供了查询和更新功能,是对并行查询功能的补充。对于 OLTP 数据库,并行 DML 操作可以加速批处理作业的运行。

配置并行 DML

OceanBase 数据库支持在 SQL 语句或会话中显式启用和禁用并行 DML。

在 SQL 语句中启用并行 DML

在 SQL 语句中启用并行 DML,请在语句中插入如下 Hint:

/*+ ENABLE_PARALLEL_DML PARALLEL(3) */

一般情况下,ENABLE_PARALLEL_DML Hint 和 PARALLEL Hint 必须配合使用才能开启并行 DML。不过,当目标表的 Schema 上指定了表级别的并行度时,仅需指定 ENABLE_PARALLEL_DML Hint。

示例如下:

同时使用 ENABLE_PARALLEL_DML Hint 和 PARALLEL(n) 参数指定并行度 n,并且 n > 1,并行度 dop=2。

  1. 创建表 t1。

    CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;
    
  2. 创建表 t2。

    CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;
    
  3. 创建表 t3。

    CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;
    
  4. 查看执行计划。

    EXPLAIN INSERT /*+ ENABLE_PARALLEL_DML PARALLEL(2) */ INTO t1 SELECT * FROM t3;
    

    返回结果如下:

    +-------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Query Plan                                                                                                                                            |
    +-------------------------------------------------------------------------------------------------------------------------------------------------------+
    | =========================================================================                                                                             |
    | |ID|OPERATOR                      |NAME           |EST.ROWS|EST.TIME(us)|                                                                             |
    | -------------------------------------------------------------------------                                                                             |
    | |0 |OPTIMIZER STATS MERGE         |               |1       |18          |                                                                             |
    | |1 | PX COORDINATOR               |               |1       |18          |                                                                             |
    | |2 |  EXCHANGE OUT DISTR          |:EX10001       |1       |18          |                                                                             |
    | |3 |   INSERT                     |               |1       |17          |                                                                             |
    | |4 |    EXCHANGE IN DISTR         |               |1       |4           |                                                                             |
    | |5 |     EXCHANGE OUT DISTR (HASH)|:EX10000       |1       |4           |                                                                             |
    | |6 |      OPTIMIZER STATS GATHER  |               |1       |4           |                                                                             |
    | |7 |       SUBPLAN SCAN           |ANONYMOUS_VIEW1|1       |4           |                                                                             |
    | |8 |        PX BLOCK ITERATOR     |               |1       |4           |                                                                             |
    | |9 |         TABLE SCAN           |t3             |1       |4           |                                                                             |
    | =========================================================================                                                                             |
    | Outputs & filters:                                                                                                                                    |
    | -------------------------------------                                                                                                                 |
    |   0 - output(nil), filter(nil), rowset=256                                                                                                            |
    |   1 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 |
    |   2 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 |
    |       dop=2                                                                                                                                           |
    |   3 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil)             |
    |       columns([{t1: ({t1: (t1.c1, t1.c2)})}]), partitions(p0),                                                                                        |
    |       column_values([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)])                   |
    |   4 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 |
    |   5 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 |
    |       (#keys=1, [column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)]), dop=2                                                                      |
    |   6 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 |
    |   7 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=256                                                                     |
    |       access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2])                                                                                              |
    |   8 - output([t3.c1], [t3.c2]), filter(nil), rowset=256                                                                                               |
    |   9 - output([t3.c1], [t3.c2]), filter(nil), rowset=256                                                                                               |
    |       access([t3.c1], [t3.c2]), partitions(p[0-3])                                                                                                    |
    |       is_index_back=false, is_global_index=false,                                                                                                     |
    |       range_key([t3.c1]), range(MIN ; MAX)always true                                                                                                 |
    +-------------------------------------------------------------------------------------------------------------------------------------------------------+
    34 rows in set
    

在 SQL 语句中禁用并行 DML

如果要禁用并行 DML,请在语句中插入如下 Hint:

/*+ DISABLE_PARALLEL_DML */

即使会话中启用了并行 DML,您也可以在指定 SQL 语句中使用 DISABLE_PARALLEL_DML Hint 禁用并行 DML。

在会话中启用并行 DML

默认情况下,即使 SQL 语句中使用了 PARALLEL Hint,并行 DML 也是不开启的,所以还需要通过在会话上开启并行 DML。

执行以下 SQL 语句在会话中启用并行 DML:

MySQL 模式
Oracle 模式
SET _FORCE_PARALLEL_DML_DOP = n;

其中 n 大于 1。

ALTER SESSION ENABLE PARALLEL DML;

Oracle 模式下,如果需要在会话中强制开启并行 DML,请运行以下 SQL 语句:

ALTER SESSION FORCE PARALLEL DML PARALLEL n;

示例如下:

Oracle 模式下在会话中强制开启并行 DML。

  1. 创建表 t1。

    CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;
    
  2. 创建表 t2。

    CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;
    
  3. 创建表 t3。

    CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;
    
  4. 在会话中强制开启并行 DML。

    ALTER SESSION FORCE PARALLEL DML PARALLEL 6;
    
  5. 查看执行计划。

    EXPLAIN INSERT INTO t2 SELECT * FROM t3;
    

    返回结果如下:

    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Query Plan                                                                                                                                                       |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | ==============================================================================                                                                                   |
    | |ID|OPERATOR                           |NAME           |EST.ROWS|EST.TIME(us)|                                                                                   |
    | ------------------------------------------------------------------------------                                                                                   |
    | |0 |OPTIMIZER STATS MERGE              |               |1       |16          |                                                                                   |
    | |1 | PX COORDINATOR                    |               |1       |16          |                                                                                   |
    | |2 |  EXCHANGE OUT DISTR               |:EX10001       |1       |15          |                                                                                   |
    | |3 |   INSERT                          |               |1       |15          |                                                                                   |
    | |4 |    EXCHANGE IN DISTR              |               |1       |2           |                                                                                   |
    | |5 |     EXCHANGE OUT DISTR (PKEY HASH)|:EX10000       |1       |2           |                                                                                   |
    | |6 |      OPTIMIZER STATS GATHER       |               |1       |2           |                                                                                   |
    | |7 |       SUBPLAN SCAN                |ANONYMOUS_VIEW1|1       |2           |                                                                                   |
    | |8 |        PX BLOCK ITERATOR          |               |1       |2           |                                                                                   |
    | |9 |         TABLE SCAN                |T3             |1       |2           |                                                                                   |
    | ==============================================================================                                                                                   |
    | Outputs & filters:                                                                                                                                               |
    | -------------------------------------                                                                                                                            |
    |   0 - output(nil), filter(nil), rowset=256                                                                                                                       |
    |   1 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |   2 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |       dop=6                                                                                                                                                      |
    |   3 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil)                  |
    |       columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-2]),                                                                                               |
    |       column_values([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)])                        |
    |   4 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), |
    | rowset=256                                                                                                                                                       |
    |   5 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), |
    | rowset=256                                                                                                                                                       |
    |       (#keys=1, [column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)]), dop=6                                                                              |
    |   6 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |   7 - output([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]), filter(nil), rowset=256                                                                                |
    |       access([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2])                                                                                                         |
    |   8 - output([T3.C1], [T3.C2]), filter(nil), rowset=256                                                                                                          |
    |   9 - output([T3.C1], [T3.C2]), filter(nil), rowset=256                                                                                                          |
    |       access([T3.C1], [T3.C2]), partitions(p[0-3])                                                                                                               |
    |       is_index_back=false, is_global_index=false,                                                                                                                |
    |       range_key([T3.C1]), range(MIN ; MAX)always true                                                                                                            |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    36 rows in set
    

需要注意的是,在 SQL 语句中启用并行 DML 时,一般使用由 Hint 指定的并行度来执行查询,其优先级高于会话中强制指定的并行度。

示例如下:

  1. 创建表 t1。

    CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;
    
  2. 创建表 t2。

    CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;
    
  3. 创建表 t3。

    CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;
    
  4. 在会话中强制开启并行 DML。

    ALTER SESSION FORCE PARALLEL DML PARALLEL 6;
    
  5. 查看执行计划。

    EXPLAIN INSERT /*+ PARALLEL(3) */ INTO t2 SELECT * FROM t3;
    

    返回结果如下:

    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Query Plan                                                                                                                                                       |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | ==============================================================================                                                                                   |
    | |ID|OPERATOR                           |NAME           |EST.ROWS|EST.TIME(us)|                                                                                   |
    | ------------------------------------------------------------------------------                                                                                   |
    | |0 |OPTIMIZER STATS MERGE              |               |1       |17          |                                                                                   |
    | |1 | PX COORDINATOR                    |               |1       |17          |                                                                                   |
    | |2 |  EXCHANGE OUT DISTR               |:EX10001       |1       |17          |                                                                                   |
    | |3 |   INSERT                          |               |1       |16          |                                                                                   |
    | |4 |    EXCHANGE IN DISTR              |               |1       |3           |                                                                                   |
    | |5 |     EXCHANGE OUT DISTR (PKEY HASH)|:EX10000       |1       |3           |                                                                                   |
    | |6 |      OPTIMIZER STATS GATHER       |               |1       |3           |                                                                                   |
    | |7 |       SUBPLAN SCAN                |ANONYMOUS_VIEW1|1       |3           |                                                                                   |
    | |8 |        PX BLOCK ITERATOR          |               |1       |3           |                                                                                   |
    | |9 |         TABLE SCAN                |T3             |1       |3           |                                                                                   |
    | ==============================================================================                                                                                   |
    | Outputs & filters:                                                                                                                                               |
    | -------------------------------------                                                                                                                            |
    |   0 - output(nil), filter(nil), rowset=256                                                                                                                       |
    |   1 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |   2 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |       dop=3                                                                                                                                                      |
    |   3 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil)                  |
    |       columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-2]),                                                                                               |
    |       column_values([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)])                        |
    |   4 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), |
    | rowset=256                                                                                                                                                       |
    |   5 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), |
    | rowset=256                                                                                                                                                       |
    |       (#keys=1, [column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)]), dop=3                                                                              |
    |   6 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256      |
    |   7 - output([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]), filter(nil), rowset=256                                                                                |
    |       access([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2])                                                                                                         |
    |   8 - output([T3.C1], [T3.C2]), filter(nil), rowset=256                                                                                                          |
    |   9 - output([T3.C1], [T3.C2]), filter(nil), rowset=256                                                                                                          |
    |       access([T3.C1], [T3.C2]), partitions(p[0-3])                                                                                                               |
    |       is_index_back=false, is_global_index=false,                                                                                                                |
    |       range_key([T3.C1]), range(MIN ; MAX)always true                                                                                                            |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    36 rows in set
    

在会话中禁用并行 DML

执行以下 SQL 语句在会话中禁用并行 DML:

MySQL 模式
Oracle 模式
SET _FORCE_PARALLEL_DML_DOP = 1;
ALTER SESSION DISABLE PARALLEL DML;

示例与执行计划解析

分区级并行更新

将根据以下 SQL 语句进行展示说明表分区并行处理功能。

  1. 创建测试表 branch_sp_tbl_src。

    CREATE TABLE branch_sp_tbl_src(id INT PRIMARY KEY, v INT) PARTITION BY KEY(id) PARTITIONS 4;
    
  2. 创建测试表 branch_sp_tbl_dest。

    CREATE TABLE branch_sp_tbl_dest LIKE branch_sp_tbl_src;
    
  3. 查看执行计划。

    执行下面 SQL 语句,将展示如何执行该插入操作。

    obclient [test]> EXPLAIN BASIC INSERT /*+enable_parallel_dml parallel(100) query_timeout(1000000000)*/ INTO branch_sp_tbl_dest SELECT id, v FROM branch_sp_tbl_src ON DUPLICATE KEY UPDATE v = v + 1;
    

    返回结果如下:

    +-------------------------------------------------------------------------------------------------------------------------------------+
    | Query Plan                                                                                                                          |
    +-------------------------------------------------------------------------------------------------------------------------------------+
    | ================================================                                                                                    |
    | |ID|OPERATOR                 |NAME             |                                                                                    |
    | ------------------------------------------------                                                                                    |
    | |0 |PX COORDINATOR           |                 |                                                                                    |
    | |1 |└─EXCHANGE OUT DISTR     |:EX10000         |                                                                                    |
    | |2 |  └─PX PARTITION ITERATOR|                 |                                                                                    |
    | |3 |    └─INSERT_UP          |                 |                                                                                    |
    | |4 |      └─SUBPLAN SCAN     |ANONYMOUS_VIEW1  |                                                                                    |
    | |5 |        └─TABLE FULL SCAN|branch_sp_tbl_src|                                                                                    |
    | ================================================                                                                                    |
    | Outputs & filters:                                                                                                                  |
    | -------------------------------------                                                                                               |
    |   0 - output(nil), filter(nil), rowset=16                                                                                           |
    |   1 - output(nil), filter(nil), rowset=16                                                                                           |
    |       dop=100                                                                                                                       |
    |   2 - output(nil), filter(nil), rowset=16                                                                                           |
    |       partition wise, force partition granule                                                                                       |
    |   3 - output(nil), filter(nil)                                                                                                      |
    |       columns([{branch_sp_tbl_dest: ({branch_sp_tbl_dest: (branch_sp_tbl_dest.id, branch_sp_tbl_dest.v)})}]), partitions(p[0-3]),   |
    |       column_values([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.id)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.v)]), |
    |       update([branch_sp_tbl_dest.v=column_conv(INT,PS:(11,0),NULL,cast(branch_sp_tbl_dest.v + 1, INT(-1, 0)))])                     |
    |   4 - output([ANONYMOUS_VIEW1.id], [ANONYMOUS_VIEW1.v]), filter(nil), rowset=16                                                     |
    |       access([ANONYMOUS_VIEW1.id], [ANONYMOUS_VIEW1.v])                                                                             |
    |   5 - output([branch_sp_tbl_src.id], [branch_sp_tbl_src.v]), filter(nil), rowset=16                                                 |
    |       access([branch_sp_tbl_src.id], [branch_sp_tbl_src.v]), partitions(p[0-3])                                                     |
    |       is_index_back=false, is_global_index=false,                                                                                   |
    |       range_key([branch_sp_tbl_src.id]), range(MIN ; MAX)always true                                                                |
    +-------------------------------------------------------------------------------------------------------------------------------------+
    27 rows in set
    

    查询计划中算子分析如下:

    • 0 号算子:表示这是一个并行执行协调器,它负责管理并行执行的进程。
    • 1 号算子:表示数据将在不同的执行节点之间进行分发。
    • 2 号算子:表示查询会遍历分区,这里 “partition wise” 意味着查询会智能地处理各个分区之间的数据。
    • 3 号算子:表示插入或更新操作。如果插入的键在表中不存在,它将执行插入操作;如果存在,则执行更新操作。
    • 4 和 5 号算子:表示对名为 branch_sp_tbl_src 的表进行全表扫描。这个表是数据源,从中选择数据来进行插入操作。

并行 DML 关联更新

说明

对于 OceanBase 数据库 V4.3.x 版本,并行 DML 从 V4.3.5 版本开始支持通过多表连接(JOIN)方式实现关联更新功能。

关联更新指在 UPDATE 语句中使用多表连接操作,基于关联表的数据更新目标表。通过并行 DML 功能,可以显著提升大规模数据更新操作的性能。

示例如下:

以下步骤展示了如何使用并行 DML 实现关联更新功能。

  1. 创建两个测试表 customers 和 orders。

    CREATE TABLE customers (
        id INT PRIMARY KEY,
        name VARCHAR(50),
        customer_level VARCHAR(10)
    );
    
    CREATE TABLE orders (
        order_id INT PRIMARY KEY,
        customer_id INT,
        discount DECIMAL(3, 2),
        amount DECIMAL(10, 2)
    );
    
  2. 插入测试数据。

    • 向 customers 表插入客户数据:

      INSERT INTO customers (id, name, customer_level) VALUES
      (1, 'Alice', 'VIP'),
      (2, 'Bob', 'NORMAL'),
      (3, 'Charlie', 'OTHER');
      
    • 向 orders 表插入订单数据:

      INSERT INTO orders (order_id, customer_id, discount, amount) VALUES
      (101, 1, NULL, 1000.00),
      (102, 2, NULL, 2000.00),
      (103, 3, NULL, 1500.00),
      (104, 1, NULL, 3000.00),
      (105, 2, NULL, 2500.00);
      
  3. 并行 DML 关联更新。

    通过 EXPLAIN 查看并行 DML 关联更新的执行计划:通过 PARALLEL Hint 指定并行度为 4,根据 customers 表中的客户等级(customer_level),更新 orders 表中的折扣字段(discount)。

    EXPLAIN UPDATE /*+ PARALLEL(4) */
        orders o JOIN customers c ON o.customer_id = c.id
    SET o.discount = CASE
        WHEN c.customer_level = 'VIP' THEN 0.9
        WHEN c.customer_level = 'NORMAL' THEN 0.95
        ELSE 1.0
        END;
    

    返回结果如下:

    +------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Query Plan                                                                                                                                                 |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | ==========================================================================                                                                                 |
    | |ID|OPERATOR                              |NAME    |EST.ROWS|EST.TIME(us)|                                                                                 |
    | --------------------------------------------------------------------------                                                                                 |
    | |0 |DISTRIBUTED UPDATE                    |        |3       |50          |                                                                                 |
    | |1 |└─PX COORDINATOR                      |        |3       |3           |                                                                                 |
    | |2 |  └─EXCHANGE OUT DISTR                |:EX10001|3       |3           |                                                                                 |
    | |3 |    └─SHARED HASH JOIN                |        |3       |3           |                                                                                 |
    | |4 |      ├─EXCHANGE IN DISTR             |        |3       |2           |                                                                                 |
    | |5 |      │ └─EXCHANGE OUT DISTR (BC2HOST)|:EX10000|3       |2           |                                                                                 |
    | |6 |      │   └─PX BLOCK ITERATOR         |        |3       |1           |                                                                                 |
    | |7 |      │     └─TABLE FULL SCAN         |c       |3       |1           |                                                                                 |
    | |8 |      └─PX BLOCK ITERATOR             |        |5       |1           |                                                                                 |
    | |9 |        └─TABLE FULL SCAN             |o       |5       |1           |                                                                                 |
    | ==========================================================================                                                                                 |
    | Outputs & filters:                                                                                                                                         |
    | -------------------------------------                                                                                                                      |
    |   0 - output(nil), filter(nil)                                                                                                                             |
    |       table_columns([{o: ({orders: (o.order_id, o.customer_id, o.discount, o.amount)})}]),                                                                 |
    |       update([o.discount=column_conv(DECIMAL_INT,PS:(3,2),NULL,CASE WHEN c.customer_level = 'VIP' THEN cast(0.9, DECIMAL_INT(3, 2)) WHEN c.customer_level  |
    |       = 'NORMAL' THEN 0.95 ELSE cast(1.0, DECIMAL_INT(3, 2)) END)])                                                                                        |
    |   1 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16                                          |
    |   2 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16                                          |
    |       dop=4                                                                                                                                                |
    |   3 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16                                          |
    |       equal_conds([o.customer_id = c.id]), other_conds(nil)                                                                                                |
    |   4 - output([c.id], [c.customer_level]), filter(nil), rowset=16                                                                                           |
    |   5 - output([c.id], [c.customer_level]), filter(nil), rowset=16                                                                                           |
    |       dop=4                                                                                                                                                |
    |   6 - output([c.id], [c.customer_level]), filter(nil), rowset=16                                                                                           |
    |   7 - output([c.id], [c.customer_level]), filter(nil), rowset=16                                                                                           |
    |       access([c.id], [c.customer_level]), partitions(p0)                                                                                                   |
    |       is_index_back=false, is_global_index=false,                                                                                                          |
    |       range_key([c.id]), range(MIN ; MAX)always true                                                                                                       |
    |   8 - output([o.order_id], [o.customer_id], [o.discount], [o.amount]), filter(nil), rowset=16                                                              |
    |   9 - output([o.order_id], [o.customer_id], [o.discount], [o.amount]), filter(nil), rowset=16                                                              |
    |       access([o.order_id], [o.customer_id], [o.discount], [o.amount]), partitions(p0)                                                                      |
    |       is_index_back=false, is_global_index=false,                                                                                                          |
    |       range_key([o.order_id]), range(MIN ; MAX)always true                                                                                                 |
    +------------------------------------------------------------------------------------------------------------------------------------------------------------+
    38 rows in set
    

使用限制与注意事项

  • 禁用并行 DML 时,即使在 SQL 语句中使用 PARALLEL Hint,也不会执行并行 DML。
  • 在会话中启用并行 DML 时,则并行执行对此会话中的所有 DML 语句都会生效。如果 SQL 语句通过 ENABLE_PARALLEL_DML Hint 启用并行 DML 时,则并行执行仅对指定语句生效。但是,如果没有具有并行属性的表,或者违反了并行操作的限制,即使启用了并行 DML,DML 操作仍然会串行执行。

并行 DML 支持的场景

场景 INSERT UPDATE DELETE MERGE INTO
表上存在外键/TRIGGER(触发器)/PL UDF(用户自定义函数)/唯一索引

说明

不能明确是否会触发触发器:当触发器与 DML 操作无关时,不会触发触发器时,会继续走并行 DML。例如,在 UPDATE 触发器的表上执行 INSERT、DELETE 等操作走并行 DML,执行 UPDATE 操作无法走并行 DML。

不支持 不支持 不支持 不支持
多表 DML INSERT ALL 语法,不支持并行 DML 支持关联 UPDATE 并行。

说明

  • 对于 OceanBase 数据库 V4.3.x 版本,从 V4.3.5 版本开始支持关联 UPDATE 并行。
  • 对于 OceanBase 数据库 V4.2.x 版本,从 V4.2.5 BP3 版本开始支持关联 UPDATE 并行。

同 UPDATE 语法不支持
自增列 部分场景支持并行 DML,详细介绍可参见下文示例。 支持 支持 支持(seq)
ArrayBinding batch 优化 不支持 不支持 不支持 不支持
使用 USER_VARIABLE 不支持 不支持 不支持 不支持
IGNORE 不支持 不支持 不支持 语法不支持
DBLink 不支持 不支持 不支持 不支持
其他 以下语句不支持并行 DML:
  • INSERT ... VALUES ...
  • INSERT INTO ON DUPLICATE KEY UPDATE
  • REPLACE
包含 ON UPDATE CURRENT_TIMESTAMP 列不支持

INSERT 的写入表有自增列时,假如自增列是主键或者分区键时,并且该列被指定时不支持并行 DML。

示例如下:

  1. 创建表 tbl1,其中列 col1 为自增列并指定为主键。

    CREATE TABLE tbl1(col1 INT AUTO_INCREMENT PRIMARY KEY, col2 INT, col3 INT);
    
  2. 创建表 tbl2,其中列 col1 为自增列。

    CREATE TABLE tbl1(col1 INT AUTO_INCREMENT, col2 INT, col3 INT);
    
  3. 创建表 tbl3。

    CREATE TABLE tbl3(col1 INT, col2 INT, col3 INT);
    
  4. INSERT 的写入数据时,因为自增列 col1 是主键,所以不支持并行 DML。

    INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl1 SELECT * FROM tbl3;
    
  5. INSERT 的写入数据时,因为未指定列 col1,所以支持并行 DML。

    INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl1(col2, col3) SELECT col2, col3 FROM tbl3;
    
  6. INSERT 的写入数据时,因为列 col1 只是自增列,所以支持并行 DML。

    INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl2 SELECT * FROM tbl3;
    

本文目录

配置并行 DML在 SQL 语句中启用并行 DML在 SQL 语句中禁用并行 DML在会话中启用并行 DML在会话中禁用并行 DML示例与执行计划解析分区级并行更新并行 DML 关联更新使用限制与注意事项并行 DML 支持的场景
有帮助
无帮助
反馈
AI

OceanBase

OceanBase 海扬数据库始创于 2010 年,是完全自主研发的数据库公司。2020年开始独立商业化运作,历经15年大规模核心场景验证,目前是中国数据库的领军企业之一。从分布式数据库到 AI 数据库,为企业提供安全、稳定、可扩展的数据底座,推动数据基础设施全面拥抱 AI 时代。

关于我们

关于 OceanBase最新动态资质荣誉客户专家委员会招贤纳士合作伙伴年度发布会开发者大会

资源与服务

支持与服务文档知识库软件与工具下载培训与认证在线体验数据库专题视频

社区

快速上手开发者中心博客活动学习问答GitHub

数据库百科

分布式数据库国产数据库OLTP 数据库OLAP 数据库HTAP 数据库数据库向量数据库向量检索

联系我们

服务热线:
400-109-0633
商务咨询
培训认证技术支持媒体合作
京公网安备11010802047223号京公网安备11010802047223号
京ICP备20024574号-1
合字B1.B2-20250395
网站服务协议隐私协议安全响应协议
OceanBase 版权所有 © 2026 基础资源和备案服务由阿里云提供