---
title: 关联更新如何选择 update 还是 merge into-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于关联更新如何选择 update 还是 merge into相关的常见问题和使用技巧，帮助您快速解决关联更新如何选择 update 还是 merge into的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 关联更新如何选择 update 还是 merge into

更新时间：2026-05-28 02:06

适用版本： V2.1.x、V2.2.x、V3.1.x、V3.2.x、V4.0.x、V4.1.x、V4.2.x 内容类型：Troubleshoot  

本文讨论关联更新，需要选择 Update 还是 Merge into 语法以及他俩的优劣。

## 适用版本

OceanBase 数据库所有版本。

## 详细内容

示例表结构以及数据。

```shell
create table test1 (a int,b varchar(100));
create table test2 (a int,b varchar(100));
insert into test1 values(1,'张三');
insert into test1 values(2,'李四');
insert into test2 values(1,'张三_NEW');

```

此时如果需要关联 test2 表更新 test1 表中 a 字段重复的行，可以采用关联 update 和 merge into 的两种写法。

例如：

```shell
update test1 t1 set t1.b=(select b from test2 where t1.a=t2.a)
where exists (select 1 from test1 t3 where t3.a=t1.a);

```

或者：

```shell
merge into test1 t1 using test2 t2
on (t1.a=t2.a)
when matched then
update set t1.b=t2.b;

```

虽然语义完全一样但是 update 的语法一次只更新一行记录，所以只能使用嵌套循环的方式进行更新。如果遇到关联的表数据量过多或者没有有效索引导致 SQL 不适合走嵌套循环的场景，那么使用 update 进行关联更新就不是一个很好的方案，此时建议使用 merge into 实现对两表使用 hash join 或者 merge join 的方式一次性更新表中的多行数据。

查看关联 update 的执行计划，其中 SUBPLAN FILTER 表示使用嵌套循环的方式对 T1 表进行更新。

```shell
Query Plan: ==========================================
|ID|OPERATOR         |NAME|EST. ROWS|COST|
------------------------------------------
|0 |UPDATE           |    |1        |139 |
|1 | SUBPLAN FILTER  |    |1        |138 |
|2 |  MERGE SEMI JOIN|    |1        |93  |
|3 |   SORT          |    |2        |47  |
|4 |    TABLE SCAN   |T1  |2        |46  |
|5 |   SORT          |    |1        |46  |
|6 |    TABLE SCAN   |T3  |1        |46  |
|7 |  TABLE SCAN     |T2  |1        |46  |
==========================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil), table_columns([{TEST1: ({TEST1: (T1.__pk_increment, T1.A, T1.B)})}]),
update([T1.B=column_conv(VARCHAR2,utf8mb4_bin,length:100,NULL,subquery(1))])
1 - output([T1.__pk_increment], [T1.A], [T1.B], [column_conv(VARCHAR2,utf8mb4_bin,length:100,NULL,subquery(1))]), filter(nil),
exec_params_([T1.A]), onetime_exprs_(nil), init_plan_idxs_(nil)
2 - output([T1.__pk_increment], [T1.A], [T1.B]), filter(nil),
equal_conds([T3.A = T1.A]), other_conds(nil)
3 - output([T1.__pk_increment], [T1.A], [T1.B]), filter(nil), sort_keys([T1.A, ASC])
4 - output([T1.B], [T1.A], [T1.__pk_increment]), filter(nil),
access([T1.B], [T1.A], [T1.__pk_increment]), partitions(p0)
5 - output([T3.A]), filter(nil), sort_keys([T3.A, ASC])
6 - output([T3.A]), filter(nil),
access([T3.A]), partitions(p0)
7 - output([T2.B]), filter([? = T2.A]),
access([T2.A], [T2.B]), partitions(p0)

```

查看 merge into 的执行计划可以看到 T1 表和 T2 表采用了 merge join 的关联方式。

```shell
obclient [SYS]> explain merge into test1 t1 using test2 t2 on (t1.a=t2.a) when matched then update set t1.b=t2.b\G
*************************** 1. row ***************************
Query Plan: ================================================
|ID|OPERATOR               |NAME|EST. ROWS|COST|
------------------------------------------------
|0 |MERGE                  |    |1        |93  |
|1 | MERGE RIGHT OUTER JOIN|    |1        |93  |
|2 |  SORT                 |    |2        |47  |
|3 |   TABLE SCAN          |T1  |2        |46  |
|4 |  SORT                 |    |1        |46  |
|5 |   TABLE SCAN          |T2  |1        |46  |
================================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil),
columns([{TEST1: ({TEST1: (T1.__pk_increment, T1.A, T1.B)})}]), partitions(p0),
update([T1.B=column_conv(VARCHAR2,utf8mb4_bin,length:100,NULL,T2.B)]),
insert_conds(nil), update_conds(nil), delete_conds(nil)
1 - output([T2.B], [T1.__pk_increment], [T1.A], [T1.B]), filter(nil),
equal_conds([T1.A = T2.A]), other_conds(nil)
2 - output([T1.__pk_increment], [T1.A], [T1.B]), filter(nil), sort_keys([T1.A, ASC])
3 - output([T1.__pk_increment], [T1.A], [T1.B]), filter(nil),
access([T1.__pk_increment], [T1.A], [T1.B]), partitions(p0)
4 - output([T2.B], [T2.A]), filter(nil), sort_keys([T2.A, ASC])
5 - output([T2.A], [T2.B]), filter(nil),
access([T2.A], [T2.B]), partitions(p0)

```

使用 hint 让 merge into 的语句走 hash join 的关联方式，语句和执行计划如下。

```shell
obclient [SYS]> explain  merge /*+use_hash(t2 t1)*/ into test1 t1 using test2 t2 on (t1.a=t2.a) when matched then update set t1.b=t2.b\G
*************************** 1. row ***************************
Query Plan: =========================================
|ID|OPERATOR        |NAME|EST. ROWS|COST|
-----------------------------------------
|0 |MERGE           |    |1        |93  |
|1 | HASH OUTER JOIN|    |1        |93  |
|2 |  TABLE SCAN    |T2  |1        |46  |
|3 |  TABLE SCAN    |T1  |2        |46  |
=========================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil),
columns([{TEST1: ({TEST1: (T1.__pk_increment, T1.A, T1.B)})}]), partitions(p0),
update([T1.B=column_conv(VARCHAR2,utf8mb4_bin,length:100,NULL,T2.B)]),
insert_conds(nil), update_conds(nil), delete_conds(nil)
1 - output([T2.B], [T1.__pk_increment], [T1.A], [T1.B]), filter(nil),
equal_conds([T1.A = T2.A]), other_conds(nil)
2 - output([T2.A], [T2.B]), filter(nil),
access([T2.A], [T2.B]), partitions(p0)
3 - output([T1.__pk_increment], [T1.A], [T1.B]), filter(nil),
access([T1.__pk_increment], [T1.A], [T1.B]), partitions(p0)

```

但是 merge into 的语句也不是在所有场景都要优于关联 update。我们知道 merge into 的完整语法为：

```
merge into target表 using (select ... from source表) on(关联条件)
when matched then update
when not matched then insert

```

当 matched 和 not matched 同时存在的时候，是只能通过 source 表来外连接 target 表的这种执行方式，如果只有 matched 存在，not matched 不存在的场景，在 Oracle 是可以优化成内连接的，但是 OceanBase 数据库目前对 merge into 语句即使不存在 not matched 的语句时也必须是外连接，这导致了 OceanBase 数据库没有办法走 target 表作为驱动表嵌套循环 source 表的执行计划。

例如：对应的数据分布为 TEST1 表数据量非常小甚至为空，而 TEST2 表非常大，我们希望让 TEST1 表嵌套循环 TEST2 表，可以将 merge into 改写成 update 语句或者变通的修改 merge into 语句将原 source 表在 using 内部先和 target 表 join 一下让新 source 表的结果集变小。

```
merge into test1 t1 using （select temp1.* from test2 temp1 join test1 temp2  on temp1.a=temp2.a)t2
on (t1.a=t2.a)
when matched then
update set t1.b=t2.b;

```

Previous

[行存，列存与优化器选择 DOP 相关 FAQs](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000002896426)

Next

[current_timestamp 列插入 default 值出现正确性问题](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000100774) ![有帮助](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) 咨询热线
