---
title: "并行执行分类与优化 - OceanBase 数据库 V4.6.0 | OceanBase 文档中心"
description: 并行执行分类与优化 OceanBase 数据库提供了多种语句的并行执行支持，包括以下几个主要类别： 并行查询 并行 DML 并行 DDL 并行 LOAD DATA 并发 DDL 并行查询 主要应用场景 SELECT 语句及其子查询 DML 语句（ INSERT / UPDATE / DELETE ）的查询部分 外表查…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.6.0

# 并行执行分类与优化

更新时间：2026-06-30 09:28:55

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.6.0/zh-CN/700.reference/1000.performance-tuning-guide/500.sql-optimization/350.parallel-execution/150.classification-of-parallel-execution.md)  

OceanBase 数据库提供了多种语句的并行执行支持，包括以下几个主要类别：

- 并行查询
 - 并行 DML
 - 并行 DDL
 - 并行 `LOAD DATA`
 - 并发 DDL

## 并行查询

### 主要应用场景

- `SELECT` 语句及其子查询
 - DML 语句（`INSERT`/`UPDATE`/`DELETE`）的查询部分
 - 外表查询

### 决策过程

并行查询的执行决策涉及两个关键方面：

1. **是否执行并行查询：**

      - 如果查询中使用了 `PARALLEL` Hint，会话开启了并行查询，或者 `TABLE` 属性指定了并行，将启用并行查询。
 2. **确定并行度：**

      - 对于基表扫描或索引扫描 DFO，其并行度由 `PARALLEL` Hint、会话并行属性，或 `TABLE` 属性来决定。
      - 如果运行时检测到某 DFO 访问的数据不足一个宏块，其运行时并行度会局部自动降低。
      - `JOIN` 等中间节点的 DFO 并行度继承自 `JOIN` 左支子 DFO 的并行度。
      - 部分 DFO 不允许并行执行（例如计算 `ROWNUM` 的节点），它们的并行度会被强制设为 1。

## 并行 DML

大多场景下，通过并行 DML（Parallel DML，简称 PDML）可以显著提升数据导入、更新和删除操作的性能。

### DML 并行度

DML 的并行度与查询部分的并行度一致。启用并行 DML 时，查询部分将自动启用并行。读取的数据根据待更新表的分区位置进行重分布，然后由多个线程并行执行 DML，每个线程负责若干个分区。

- 当并行度与目标表的分区数存在倍数关系时，通常能达到最佳性能。当并行度大于分区数时，会有多个线程处理同一个分区的数据；当并行度小于分区数时，单个线程可能处理多个分区的数据，并且每个线程处理的分区不重合。

     - 并行度大于目标表分区数时，建议并行度为分区数的整数倍。通常，同时向一个分区插入数据的线程数不应超过 4 个，因为超过这个值后扩展性受到限制，日志同步可能成为瓶颈，另外还有一些分区级别的锁同步开销。
     - 并行度小于目标表分区数时，建议分区数是并行度的整数倍，以避免插入工作量不均衡的情况。

### 索引表处理策略

并行 DML 支持自动维护索引表。

- 对于本地索引，存储层会在并行 DML 更新主表时自动处理本地索引。
 - 对于全局索引，使用并行 DML 框架时，会生成相应计划以维护全局索引。

下面是针对两个全局索引的处理流程：

1. DFO1 首先负责主表的更新。
 2. DFO1 然后将全局索引 1 和全局索引 2 所需数据传递给 DFO2，DFO2 负责更新全局索引表 1。
 3. 最终，DFO2 将全局索引 2 所需数据传递给 DFO3，DFO3 完成全局索引表 2 的更新。

![并行 DML 索引](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer/V4.2.0/px-index-table.jpg)

上述策略适用于所有 `INSERT`、`DELETE`、`UPDATE` 语句。对于 `MERGE` 语句，索引维护操作集中在一个 `DFO` 中处理，如下图所示：

1. DFO1 首先负责主表的更新。
 2. DFO1 然后将全局索引 1 和全局索引 2 所需数据传递给 DFO2，DFO2 内部逐个完成全部全局索引的维护操作。

![并行 DML 索引2](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/observer/V4.2.0/px-index-table-2.png)

### 更新分区键的处理策略

对于 `UPDATE` 语句，当主表或全局索引表的分区键被更新时，需要执行 `Row Movement` 操作，即将旧数据从旧分区删除，然后将新数据插入新分区。在发生 Row Movement 时，将 `UPDATE` 操作分解为 `DELETE` 和 `INSERT` 两个步骤，即将涉及 `Row Movement` 的 `UPDATE` DFO 拆分为两个 DFO。第一个 DFO 负责 `DELETE`，第二个 DFO 负责 `INSERT`。为避免主键冲突，必须确保 `DELETE` DFO 完全执行完成后才能开始执行 `INSERT` DFO。

### 事务处理

OceanBase 数据库并行 DML 和普通 DML 语句一样，完全支持事务处理。并行 DML 语句可以和其它查询语句一起出现在同一个事务中，执行完成并行 DML 语句后无需立即提交事务，就可以在后继的查询语句中读取到 DML 语句的结果。

在 OceanBase 数据库 V4.1.0 之前版本，当并行 DML 执行时间超长时，需要给租户配置项 `undo_retention` 设置合适的值，否则可能发生 `-4138 (OB_SNAPSHOT_DISCARDED)` 错误，导致 SQL 在内部反复重试，直至超时。

- `undo_retention` 字面意思是 Undo 的保留位点，即从当前时间回溯多长时间的 Undo 日志是保留下来的。对于 OceanBase 数据库来说，是将该时段的所有数据多版本保留下来。当并行 DML 执行时间超过 `undo_retention` 设定的时间时，多版本数据可能被淘汰，当 DML 中的任何后继操作试图访问淘汰的多版本数据时，就会触发 `OB_SNAPSHOT_DISCARDED` 报错。
 - `undo_retention` 的默认值是 30 分钟，这意味着在默认情况下，如果并行 DML 语句 30 分钟内不能执行完成，无论语句的超时时间设定为多少，语句都可能执行超时并报错。一般来说，如果业务中的最长并行 DML 的执行时间为 2h 时，`undo_retention` 可以设置为 2.5h。`undo_retention` 不能随意设置为极大值，那会导致多版本数据无法回收，磁盘爆盘。

从 OceanBase 数据库 V4.1.0 版本起，并行 DML 的执行不再依赖 `undo_retention` 设定。多版本数据会根据事务版本号回收，只要事务还活跃，事务对应的版本号能读到的内容就不会回收。不过，数据盘满的场景是例外，此时还是会强行回收多版本数据，并行 DML 会收到 `OB_SNAPSHOT_DISCARDED` 报错，并自动重试整个 SQL。

### 旁路导入

在内存空间不足的情况下，由于并行 DML 容易报告内存不足错误，未经旁路导入路径的并行 DML 会先将数据写入 MemTable，然后通过转储和合并的方式写入磁盘。由于并行 DML 将数据快速写入 MemTable，当写入速度超过转储速度时，内存将不断增长，最终导致内存不足错误。

为解决这一问题，OceanBase 数据库的存储层引入了旁路导入功能。当并行 DML 使用旁路导入功能执行 INSERT 语句时，数据将直接绕过 MemTable 写入磁盘，既避免了内存不足问题，又提高了数据导入性能。

用户可以通过 `APPEND` Hint 开启旁路导入功能。在开始旁路导入之前，要求提交上一个事务并设置 `AUTOCOMMIT = 1`。在 OceanBase 数据库 V4.2.0 版本中，旁路导入功能必须与并行 DML 配合使用，如果未通过提示或会话开启并行 DML，则旁路导入的提示将被自动忽略。以下是语法示例：

```sql
SET AUTOCOMMIT = 1;
INSERT /*+ APPEND ENABLE_PARALLEL_DML PARALLEL(3) */ INTO t1 SELECT * FROM t2;

```

### 无法并行的 DML 操作

为确保正确的 DML 语义，下列场景中的查询部分可并行，但 DML 部分无法并行：

- 如果目标表包含 `LOCAL UNIQUE INDEX`，则 DML 部分不可并行，而查询部分仍可并行。
 - `INSERT ON DUPLICATE KEY UPDATE` 语句的 DML 部分不可并行。
 - 如果目标表包含触发器、外键，则 DML 部分不可并行。
 - 如果 DML 启用了 `IGNORE` 模式，则 DML 部分不可并行。
 - 多表的 `INSERT ALL`、`UPDATE`、`DELETE`、`MERGE INTO` 语句不可并行。
 - ArrayBinding batch 的优化不支持并行。
 - DBLink 不支持并行。
 - `INSERT...VALUES...`、`INSERT UPDATE` 或 `REPLACE` 语句不支持并行。
 - 包含 `ON UPDATE CURRENT_TIMESTAMP` 的列不支持并行。

如果发现 DML 未并行执行，可通过 `EXPLAIN EXTENDED` 命令查看 Note 字段，以确定未并行执行的原因。

### Row Movement 操作

在更新分区表的分区键时，可能会导致数据从一个分区搬迁到另一个分区。在 Oracle模式下，可以通过以下命令禁止数据跨分区搬迁：

```sql
CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) PARTITION BY HASH(c1) PARTITIONS 3;
ALTER TABLE t1 DISABLE ROW MOVEMENT;

obclient> UPDATE t1 SET c1 = c1 + 100000000;
OBE-14402: updating partition key column would cause a partition change

```

然而，并行 DML 会忽略表的 `ROW MOVEMENT` 属性，始终允许更新分区键。

## 并行 DDL

所有的并行 DDL 操作都通过特定的 Parallel DML 完成。例如，创建索引本质上是创建一个索引空表，然后并行地从主表查询出索引列数据，最后并行地插入到索引表中。OceanBase 数据库支持并行执行的 DDL 语句包括：

- `CREATE TABLE AS SELECT`
 - `ALTER TABLE`
 - `CREATE INDEX`

### 通过 HINT 指定并行度

`CREATE INDEX` 语句支持通过 `PARALLEL` Hint 开启并行，其余 DDL 都只支持 Session 变量和 `TABLE PARALLEL` 属性来开启。

语法如下：

```sql
CREATE /*+ PARALLEL(3) */ INDEX IDX ON t1(c2);

```

### 通过 SESSION 变量指定并行度

上述所有 DDL 语句都支持通过 Session 变量来指定并行度。指定并行度后，该 Session 上的所有 DDL 都自动按照该并行度并行执行，并且查询部分和修改部分都使用相同的并行度。

- 在 Oracle 模式下，使用 `ALTER SESSION` 修改并行度，语法示例如下：

  ```sql
  -- 并行创建索引
  ALTER SESSION FORCE PARALLEL DDL PARALLEL 3;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT);
  CREATE INDEX IDX ON t1(c2);

  ```

  在 OceanBase 数据库 V4.2.0 版本中，Oracle 模式下 `CREATE TABLE AS SELECT` 开启并行，使用的是 `ALTER SESSION FORCE PARALLEL DML PARALLEL`，而非 `ALTER SESSION FORCE PARALLEL DDL PARALLEL`。

  ```sql
  -- 并行 CTAS 建表
  ALTER SESSION FORCE PARALLEL DML PARALLEL 3;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT);
  CREATE TABLE t2 AS SELECT * FROM t1;

  ```
 - 在 MySQL 模式下，语法稍有不同，会使用 `SET` 语句设定 Session 变量来控制并行度。示例如下：

  ```sql
  -- 并行创建索引
  SET _FORCE_PARALLEL_DDL_DOP = 3;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT);
  CREATE INDEX IDX ON t1(c2);

  ```

  在 OceanBase 数据库 V4.2.0 版本中，MySQL 模式下 `CREATE TABLE AS SELECT` 开启并行，使用的是 `SET _FORCE_PARALLEL_DML_DOP`，而非 `SET _FORCE_PARALLEL_DDL_DOP`。

  ```sql
  -- 并行 CTAS 建表
  SET _FORCE_PARALLEL_DML_DOP = 3;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT);
  CREATE TABLE t2 AS SELECT * FROM t1;

  ```

### 通过表 PARALLEL 属性指定并行度

当 DDL 相关表上有 `PARALLEL` 属性时，可以用下面的方法开启并行 DDL。

- 在 Oracle 模式下，使用 `ALTER SESSION` 命令开启并行，语法如下：

  ```sql
  -- 并行创建索引
  ALTER SESSION ENABLE PARALLEL DDL;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3;
  CREATE INDEX IDX ON t1(c2) PARALLEL = 2;

  ```

  ```sql
  -- 并行 CTAS 建表
  ALTER SESSION ENABLE PARALLEL DML;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3;
  CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1;

  ```
 - 在 MySQL 模式下，使用 `SET` 语句设定 Session 变量来开启并行执行。示例如下：

  ```sql
  -- 并行创建索引
  SET _ENABLE_PARALLEL_DDL = 1;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3;
  CREATE INDEX IDX ON t1(c2) PARALLEL = 2;

  ```

  在 OceanBase 数据库 V4.2.0 版本中，MySQL 模式下 `CREATE TABLE AS SELECT` 开启并行，使用的是 `SET _ENABLE_PARALLEL_DML`，而非 `SET _ENABLE_PARALLEL_DDL`。

  ```sql
  -- 并行 CTAS 建表
  SET _ENABLE_PARALLEL_DML = 1;
  CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, c4 INT) PARALLEL = 3;
  CREATE TABLE t2 PARALLEL 2 AS SELECT * FROM t1;

  ```

如果同时指定了 `PARALLEL` Hint、`FORCE SESSION PARALLEL`、表级 `PARALLEL` 属性中的两个或多个，那么它们的优先级如下： `PARALLEL` Hint 优先级 > `FORCE SESSION PARALLEL` 优先级 > 表 `PARALLEL` 属性优先级

`CREATE INDEX` 语句无论是否开启并行，总是会走旁路导入（Direct Write，Bypass memtable）。

#### 注意

`CREATE TABLE AS SELECT` 语句目前（OceanBase 数据库 V4.2.0 版本）还不支持旁路导入功能，如果数据量比较大，建议先建立空表，然后使用并行 DML 旁路导入模式并行插入。

## 并行 LOAD DATA

`LOAD DATA` 的实现不是基于并行 DML，它的实现方式是：先用多个线程并行切分 csv 文件，拼成多个 `INSERT` 语句，然后用一定的并行度分发执行这些 `INSERT` 语句。

```sql
LOAD DATA /*+ parallel(2) */ infile "test.csv" INTO TABLE t1 FIELDS TERMINATED BY ',' ENCLOSED BY '"';

```

上述语句中，`PARALLEL` 选项指定加载数据的并行度，如果没有指定 `PARALLEL` Hint，则默认以 `PARALLEL` 为 4 来并行执行 `LOAD DATA`。`PARALLEL` 建议取值范围是 0 到 租户的最大 CPU 数。

## 并发 DDL

### 并行 DDL 与并发 DDL 对比

上文章节中所述的并行 DDL 的概念是指单条 DDL 操作通过使用多线程来加快执行速度，而这些操作依然是串行地处理。换句话来说，多线程可以在单一操作内并行工作，但不同的 DDL 语句不能同时进行。

而并发 DDL 则不同，其允许多条 DDL 语句彼此独立地并发执行。这项能力可以大大提高集群利用率和整体的DDL执行效率。

通过这种区分，用户可以更好地理解在特定场景下应该采取哪种策略来优化 DDL 操作的性能。

### 并发 DDL 能力

从 OceanBase V4.1.0 版本起，引入了并发 DDL 执行的能力。这一功能通过扩展 RootService 节点的 DDL 线程数量来实现，将单个 DDL 操作分解为不同阶段，并对某些阶段实施并行处理。如此，RootService 可在其节点上处理多个无冲突的 DDL 请求，其新增的 DDL 线程数量与集群规模相关联。随着集群和租户规模的扩展，DDL 执行性能亦相对提升。

OceanBase 数据库具备并发执行能力的 DDL 有：

- `TRUNCATE TABLE`：从 OceanBase V4.1.0 开始支持。
 - `CREATE TABLE`：从 OceanBase V4.2.1 开始支持。

### 使用说明与注意事项

集群在 OceanBase V4.2.1 版本或更高版本部署，或由 V4.1.0 升级到 V4.2.1 版本或更高版本后，用户无需任何额外配置即可自动开启并发建表功能。

用户可使用以下 SQL 语句查看当前租户版本状态。

```sql
SHOW PARAMETERS LIKE "compatible";

```

使用并发 DDL 操作需要注意以下事项：

- **互斥性**：并发 DDL 与串行 DDL 在逻辑上完全互斥。为获得并发 DDL 的最大吞吐率，集群在执行并发 DDL 时不应有其他串行 DDL 操作进行。
 - **节点优化**：DDL 请求总是在 RootService 节点执行。为降低网络开销，RootService 和租户 Leader 应尽可能置于同一节点。
 - **资源消耗**：提升并发 DDL 操作，特别是创建表的并发度，将增加系统负载及资源消耗。
 - **线程需求**：系统租户为应对增加的 DDL 请求，需要足够的线程资源。要达到最大吞吐率，系统租户至少需要额外 6 核 CPU 的计算资源。
 - **用户租户资源**：用户租户同样需要足够的线程来处理 DDL 请求和写内部表操作。为实现 DDL 最优性能，用户租户需配备至少额外 14 核 CPU 的计算资源。
 - **内存和存储需求**：由于并发 DDL 特别是并发表创建会在短时间内向内部表写入大量数据，从而对存储和内存提出更高的要求。当存储空间过小或内存不足以支撑数据快速落盘时，可能会限制写入速度，这将直接影响并发 DDL 的执行效率，同时也会性能影响正常业务流量的处理。

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
