功能简介
并行 DML 通过并行查询机制大幅度提高单表更新和删除操作的执行效率。通过多 Worker 并行扫描和修改数据,在数据量较大时缩短 DML 操作的执行时间。
注意:
启动和关闭并行 DML
MySQL 原生执行引擎并非通过算子(迭代器)的方式执行 DML 操作,而并行 DML 要求 DML 操作通过算子的方式执行。因此开启并行 DML 需要打开
single_delete_update_use_iterator 系统变量。该系统变量必须和 PARALLEL Hint 配合使用才能开启并行 DML。如下示例展示了两种启动并行 DML 的方式:说明:
single_delete_update_use_iterator 系统变量可以通过 set_var hint 只在某条 DML 语句中打开。-- 开启并行 DMLSET single_delete_update_use_iterator = ON;EXPLAIN format=tree UPDATE /*+ PARALLEL(4) */ t1 SET a = a - 1;EXPLAIN-> Gather (slice: 1, workers: 4) (cost=2305.65..5530.21 rows=10000)-> Update t1 (immediate) (cost=1.00..2511.52 rows=2500)-> Table scan on t1, with range parallel scan (cost=0.77..1935.48 rows=2500)-- 通过 SET_VAR Hint 设置 single_delete_update_use_iteratorSET single_delete_update_use_iterator = OFF;EXPLAIN format=tree UPDATE /*+ PARALLEL(4) */ t1 SET a = a - 1;<not executable by iterator executor>EXPLAIN format=tree UPDATE /*+ set_var(single_delete_update_use_iterator=on) PARALLEL(4) */ t1 SET a = a - 1;EXPLAIN-> Gather (slice: 1, workers: 4) (cost=2305.65..5530.21 rows=10000)-> Update t1 (immediate) (cost=1.00..2511.52 rows=2500)-> Table scan on t1, with range parallel scan (cost=0.77..1935.48 rows=2500)
关闭并行 DML,可以选择关闭
parallel_query_switch 系统变量的 force 选项且不添加 PARALLEL Hint,此时 DML 仍然会采用算子的方式执行。也可以直接关闭 single_delete_update_use_iterator 系统变量,此时 DML 使用 MySQL 原生执行方式。-- 关闭并行 DML(没有 PARALLEL HINT)SET single_delete_update_use_iterator = ON;EXPLAIN format=tree UPDATE t1 SET a = a - 1;EXPLAIN-> Update t1 (immediate) (cost=1.00..10046.08 rows=10000)-> Table scan on t1, with range parallel scan (cost=0.77..7741.94 rows=10000)-- 关闭并行 DML(不使用算子的方式执行 DML 操作)SET single_delete_update_use_iterator = OFF;EXPLAIN format=tree UPDATE t1 SET a = a - 1;<not executable by iterator executor>
执行机制
整体上并行 DML 的执行流程和其他并行查询相同,详见 并行查询概述。因为 MySQL 原生执行引擎不会通过算子的方式执行 DML 操作,只会通过这种方式执行读取部分。因此并行 DML 还会执行如下步骤:
1. 添加 DML 算子:在读取部分的查询计划上添加 DML 算子。
2. 判断是否可以并行执行:根据下面的支持场景判断 DML 是否可以并行执行。
3. 并行执行准备:可以并行执行的 DML 语句补充并行执行需要的其他结构。
支持场景与限制条件
当前并行 DML 仅支持单表 UPDATE 和单表 DELETE 语句,不满足条件的语句会自动回退为串行执行,语义与未开启并行时完全一致。
场景 | UPDATE | DELETE |
表上存在 TRIGGER(触发器)/PL UDF | 不支持 | 不支持 |
修改临时表、系统表等非 TDStore 表 | 不支持 | 不支持 |
多表 DML | 不支持 | 不支持 |
使用用户定义变量 | 不支持 | 不支持 |
IGNORE | 不支持 | 不支持 |
包含子查询 | 不支持 | 不支持 |
带 RETURNING 子句 | 不支持 | 不支持 |
其他 | 包含 ON UPDATE CURRENT_TIMESTAMP 列不支持; 修改主键 / 唯一索引 / 分区列不支持; 修改读表使用的索引列不支持 | |
并行执行说明
当前并行仅支持完全并行执行的并行计划,如果 DML 中包含并行不安全或者只能串行执行的函数或者表达式,那么会回退到串行执行。用户无需修改 SQL,结果与关闭并行功能时相同。可通过
EXPLAIN FORMAT=TREE 确认实际执行路径。并行 DML 如果采用 Dynamic Range Scan 方式进行并行扫描(详见 并行查询概述)可以根据数据分布选择两种不同的分片分配方式,由
parallel_query_switch 系统变量的 rep_group_parallel_scan 选项控制,该选项默认关闭。1. 开启该选项时,并行扫描会按 Replication Group 切分任务,并保证同一个 Replication Group 的数据由同一个并行 worker 处理,从而避免同一个 Replication Group 上并发的带锁读和修改操作导致的性能损耗,适合更新数据量较大的分区表。
2. 关闭该选项时,每个分片被一个 Worker 扫描,worker 根据实际执行的情况去动态获取分片数据。
-- t 表存放在两个 Replication Group 上-- 开启 rep_group_parallel_scanSET parallel_query_switch = 'rep_group_parallel_scan=on';EXPLAIN format=tree UPDATE /*+ PARALLEL(4) */ t1 SET a = a + 1;EXPLAIN-> Gather (slice: 1, workers: 2) (cost=2306.04..9455.55 rows=10000)-> Update t1 (immediate) with filter: (cost=1.05..5253.46 rows=5000)-> Table scan on t1, with range parallel scan (cost=0.82..4101.38 rows=5000)-- 关闭 rep_group_parallel_scanSET parallel_query_switch = 'rep_group_parallel_scan=off';EXPLAIN format=tree UPDATE /*+ PARALLEL(4) */ t1 SET a = a + 1;EXPLAIN-> Gather (slice: 1, workers: 4) (cost=2305.65..5530.21 rows=10000)-> Update t1 (immediate) (cost=1.00..2511.52 rows=2500)-> Table scan on t1, with range parallel scan (cost=0.77..1935.48 rows=2500)
与串行 DML 的差异
正确性
在相同事务隔离级别(
REPEATABLE READ 或 READ COMMITTED)下,并行 UPDATE / DELETE 与串行执行修改相同的行、产生相同的结果。影响行数相同;
并发执行时的锁获取、锁等待、锁超时等行为与串行一致;
跨节点场景下,所有 Worker 读取 Leader 在语句开始时建立的一致性快照,不会出现数据区别。
性能对比
方面 | 串行 UPDATE / DELETE | 并行 UPDATE / DELETE |
数据扫描 | 单线程顺序扫描 | 多 Worker 并行扫描 |
数据修改 | 扫描同时逐行修改 | 多 Worker 并行修改 |
适用场景 | 少量行、点查为主 | 大范围扫描、全表或大范围条件 |
写入瓶颈 | 通常不是瓶颈 | 修改行数极多时,Leader 写可能成为瓶颈 |
建议:并行 DML 适合
WHERE 条件命中大量行的场景;若仅修改少量行(如主键点查),串行执行往往更优。查询计划显示
MySQL 原生不支持以树形式 EXPLAIN FORMAT=TREE 去查看单表 UPDATE / DELETE 语句的执行计划,打开
single_delete_update_use_iterator 系统变量后可以以树形式查看执行计划,但是同样不支持 EXPLAIN ANALYZE 去查看执行计划的实际耗时。-- 关闭系统变量,和 MySQL 原生一致SET single_delete_update_use_iterator = OFF;EXPLAIN format=tree UPDATE t1 SET a = a - 1;<not executable by iterator executor>-- 开启系统变量SET single_delete_update_use_iterator = ON;EXPLAIN format=tree UPDATE t1 SET a = a - 1;EXPLAIN-> Update t1 (immediate) (cost=1.00..10046.08 rows=10000)-> Table scan on t1, with range parallel scan (cost=0.77..7741.94 rows=10000)
常见问题
加了 PARALLEL Hint 但计划仍是串行的?
可能原因:语句含有上文列出的限制(如 LIMIT、子查询)或者无法完全并行的表达式。请检查 OPTIMIZER TRACE 中并行优化部分的
cause,或去掉限制语法后重试。并行 DML 比串行还慢?
并行适合大批量数据的读取和修改。若
WHERE 仅命中少量行,或修改行数很多导致 Leader 写成为瓶颈,串行可能更快。请根据实际需要选择是否开启并行 DML。跨节点表能否使用?
可以。数据分布在多个节点时,各节点 Worker 并行扫描,Leader 统一修改并提交,对用户透明。