Oracle 用merge 实现对一张表的操作存在则修改不存在则插入

本文通过具体示例展示了如何使用Oracle数据库的MERGE语句来实现条件更新与插入操作,并验证了其效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

--测试数据
create table table1(id varchar2(100),name varchar2(1000),address varchar2(1000));
insert into table1(id,name,address)values('01001','影子','河北') ;
commit;

--插入
merge into table1 t1
using (select '01002' id,'影子' name,'河北' address from dual) t2
on (t1.id = t2.id)
when matched then
     update set t1.name = t2.name, t1.address = t2.address
when not matched then
     insert values (t2.id, t2.name,t2.address);
commit;

--查询结果
select * from table1
01001    影子    河北
01002    影子2    辽宁

--更新
merge into table1 t1
using (select '01001' id,'不是影子' name,'山西' address from dual) t2
on (t1.id = t2.id)
when matched then
     update set t1.name = t2.name, t1.address = t2.address
when not matched then
     insert values (t2.id, t2.name,t2.address);
commit;


--查询结果
select * from table1

01001    不是影子    山西
01002    影子2    辽宁

--删除测试数据
drop table table1;

### Oracle 中 `MERGE INTO` 语句导致锁的原因 在 Oracle 数据库中,`MERGE INTO` 是一种强大的 SQL 语法,用于在一个操作中完成更新 (`UPDATE`) 和插入 (`INSERT`) 的功能。然而,在某些情况下,该语句可能会引发锁问题。 #### 锁定行为分析 当执行 `MERGE INTO` 时,数据库会根据目标同部分施加同的锁定机制。具体来说: 1. **分区级别的锁定** 如果目标是一个分区,则 `MERGE INTO` 只会对涉及到的特定分区进行锁定,而是整个[^1]。这意味着只有那些满足合并条件的数据所在的分区会被锁定,其他未受影响的分区仍然可以正常读写。 2. **行级锁定 vs 级锁定** 对于非分区,如果 `USING` 子句中的数据源(即子查询或另一张)返回大量记录并触发多个 DML 操作,那么可能造成更广泛的锁定范围。通常情况下,`MERGE INTO` 使用的是行级锁定 (Row-Level Locking),但如果事务未能及时提交或者存在死锁情况,则可能导致升级为级锁定 (Table-Level Locking)[^3]。 3. **并发控制的影响** 当多条 `MERGE INTO` 语句试图同时修改同一组数据时,由于 Oracle 默认采用 MVCC (Multi-Version Concurrency Control) 来管理一致性视图,因此可能发生等待现象甚至死锁。这种竞争关系也会间接增加锁冲突的概率。 --- ### 解决方案 针对由 `MERGE INTO` 引发的锁问题,可以从以下几个方面入手优化和规避风险: #### 1. 减少锁定粒度 - 尽量将大容量的操作拆分为多次较小规模的任务来减少单次处理的数据量。 - 利用索引来加速定位符合条件的目标行,从而降低扫描整的可能性[^2]。 #### 2. 提高并发性能 - 确保所有参与运算的对象都具有合适的统计信息以便 CBO (Cost-Based Optimizer) 做出最佳决策路径规划。 - 配置合理的隔离级别以平衡一致性和吞吐率之间的矛盾;例如可考虑设置 READ COMMITTED 而是 SERIALIZABLE。 #### 3. 定期监控与诊断 - 启用 AWR 报告或其他工具持续跟踪长时间运行的 session 是否持有过多资源锁。 - 查看 v$lock 动态视图找出具体的阻塞源头及其上下文环境。 #### 4. 修改逻辑设计 - 若业务允许的话,可以把复杂的 `MERGE INTO` 替换成分离式的单独 update/insert 步骤,并显式指定各自的 where 条件加以约束。 - 或者引入临时中间层存储阶段性的变更结果后再统一应用至最终目的端。 --- ### 示例代码调整建议 以下是经过改进后的示例实现方式之一,旨在缓解潜在的锁争用状况: ```sql -- 创建全局临时保存增量变化集 CREATE GLOBAL TEMPORARY TABLE temp_changes ( id NUMBER, col_a VARCHAR2(50), col_b DATE ); -- 插入待同步的新旧差异项 INSERT INTO temp_changes(id, col_a, col_b) SELECT b.id, b.col_a, SYSDATE FROM source_table b WHERE ...; COMMIT; -- 确认暂存完毕再继续后续动作 BEGIN TRANSACTION; FOR rec IN (SELECT * FROM temp_changes) LOOP BEGIN UPDATE target_table t SET t.col_x = rec.col_a, t.last_update_time = rec.col_b WHERE t.id = rec.id AND ROWNUM=1; IF SQL%ROWCOUNT = 0 THEN INSERT INTO target_table VALUES(rec.id, rec.col_a, rec.col_b); END IF; EXCEPTION WHEN OTHERS THEN NULL; -- 忽略个别失败情形影响整体流程推进 END; END LOOP; COMMIT; DROP TABLE temp_changes PURGE; ``` 以上脚本通过分步化的方式降低了每次交互所影响的单元数量,同时也便于调试排查异常点所在位置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值