以前只考虑 merge into 只是在特定场合下方便才使用的,今天才发现,merge into 竟然会比 update 在更新数据时有这么大的改进。
其实呢,merge into部分的update和update也没啥不同的,不同的地方在于使用merge into后执行计划变了。 赶紧测试看看,但是看到下面的结果,我和我的小伙伴惊呆了~
测试数据:
create table test1 as select * from dba_objects where rownum<=10000;--10000条记录
create table test2 as select * from dba_objects;--13438条记录
更新相同的数据,看看下面merge into和update相比性能上有何改进。
测试1:update
SQL> alter system flush shared_pool;
系统已更改。
SQL> alter system flush buffer_cache;
系统已更改。
SQL> set linesize 400 pagesize 400
SQL> set autot trace
SQL> set timing on
SQL> update test1 t1
2 set t1.object_name =
3 (select t2.object_name
4 from test2 t2
5 where t2.object_id = t1.object_id);
已更新10000行。
已用时间:  00: 00: 25.24
执行计划
----------------------------------------------------------
Plan hash value: 3883393169
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 9606 | 741K| 518K (2)| 01:43:46 |
| 1 | UPDATE | TEST1 | | | | |
| 2 | TABLE ACCESS FULL| TEST1 | 9606 | 741K| 40 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| TEST2 | 167 | 13193 | 53 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("T2"."OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement (level=4)
统计信息
----------------------------------------------------------
234 recursive calls
10665 db block gets
2282027 consistent gets
335 physical reads
1631056 redo size
685 bytes sent via SQL*Net to client
705 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
17 sorts (memory)
0 sorts (disk)
10000 rows processed
测试2:merge into
SQL> alter system flush shared_pool;
系统已更改。
已用时间:  00: 00: 00.33
SQL> alter system flush buffer_cache;
系统已更改。
已用时间:  00: 00: 00.11
SQL> merge into test1 t1
2 using test2 t2
3 on (t1.object_id = t2.object_id)
4 when matched then
5 update set t1.object_name = t2.object_name;
10000 行已合并。
已用时间:  00: 00: 01.14
执行计划
----------------------------------------------------------
Plan hash value: 818823782
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 9607 | 1238K| | 373 (1)| 00:00:05 |
| 1 | MERGE | TEST1 | | | | | |
| 2 | VIEW | | | | | | |
|* 3 | HASH JOIN | | 9607 | 3996K| 2168K| 373 (1)| 00:00:05 |
| 4 | TABLE ACCESS FULL| TEST1 | 9606 | 2054K| | 40 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| TEST2 | 16669 | 3369K| | 53 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- dynamic sampling used for this statement (level=4)
统计信息
----------------------------------------------------------
359 recursive calls
10265 db block gets
964 consistent gets
343 physical reads
2725336 redo size
685 bytes sent via SQL*Net to client
698 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
23 sorts (memory)
0 sorts (disk)
10000 rows processed 测试结果对比:update和merge into 都更新1w条记录,update耗时25.24,逻辑读消耗2282027;merge into 耗时01.14s,消耗逻辑读964.相差太大了。
其实看着执行计划,这个结果也很容易理解:update采用的类似nested loop的方式,对更新的每一行,都会对查询的表扫描一次;merge into这里选择的是hash join,
则针对每张表都是做了一次 full table scan,对每张表都只是扫描一次。
具体看下面的结果:
SQL> set autot off
SQL> update /*+gather_plan_statistics*/test1 t1
2 set t1.object_name =
3 (select t2.object_name
4 from test2 t2
5 where t2.object_id = t1.object_id);
已更新10000行。
已用时间:  00: 00: 27.26
SQL> select * from table(dbms_xplan.display_cursor(null,null,'iostats'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------
SQL_ID c0pc2fq4pj4zq, child number 0
-------------------------------------
update /*+gather_plan_statistics*/test1 t1 set t1.object_name =
(select t2.object_name from test2 t2 where
t2.object_id = t1.object_id)
Plan hash value: 3883393169
--------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 |00:00:27.26 | 1800K|
| 1 | UPDATE | TEST1 | 1 | | 0 |00:00:27.26 | 1800K|
| 2 | TABLE ACCESS FULL| TEST1 | 1 | 9606 | 10000 |00:00:00.04 | 134 |
|* 3 | TABLE ACCESS FULL| TEST2 | 10000 | 167 | 10000 |00:00:27.03 | 1800K|
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("T2"."OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement (level=4)
已选择26行。
SQL> merge /*+gather_plan_statistics*/into test1 t1
2 using test2 t2
3 on (t1.object_id = t2.object_id)
4 when matched then
5 update set t1.object_name = t2.object_name;
10000 行已合并。
已用时间:  00: 00: 00.25
SQL> select * from table(dbms_xplan.display_cursor(null,null,'iostats'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------
SQL_ID cg8wb3hrjx2bd, child number 0
-------------------------------------
merge /*+gather_plan_statistics*/into test1 t1 using test2 t2 on
(t1.object_id = t2.object_id) when matched then update set
t1.object_name = t2.object_name
Plan hash value: 818823782
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 1 | | 0 |00:00:00.22 | 10568 | 1 |
| 1 | MERGE | TEST1 | 1 | | 0 |00:00:00.22 | 10568 | 1 |
| 2 | VIEW | | 1 | | 10000 |00:00:00.05 | 314 | 0 |
|* 3 | HASH JOIN | | 1 | 9607 | 10000 |00:00:00.05 | 314 | 0 |
| 4 | TABLE ACCESS FULL| TEST1 | 1 | 9606 | 10000 |00:00:00.01 | 134 | 0 |
| 5 | TABLE ACCESS FULL| TEST2 | 1 | 16669 | 13438 |00:00:00.01 | 180 | 0 |
-------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- dynamic sampling used for this statement (level=4)
已选择28行。

merge into 和 update 的效率对比的更多相关文章

  1. PLSQL_性能优化系列17_Oracle Merge Into和Update更新效率

    2015-05-21 Created By BaoXinjian 一.摘要 以前只考虑 merge into 只是在特定场合下方便才使用的,今天才发现,merge into 竟然会比 update 在 ...

  2. C#调用C++ memcpy实现各种参数类型的内存拷贝 VS marshal.copy的实现 效率对比

    using System; using System.Runtime.InteropServices; using System.IO; namespace tx { struct ST { publ ...

  3. Merge into语句用法及其效率问题

    Merge into语句用法及其效率问题 /*Merge into 详细介绍MERGE语句用来合并UPDATE和INSERT语句.通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询, ...

  4. string中Insert与Format效率对比、String与List中Contains与IndexOf的效率对比

    关于string的效率,众所周知的恐怕是“+”和StringBuilder了,这些本文就不在赘述了.关于本文,请先回答以下问题(假设都是基于多次循环反复调用的情况下):1.使用Insert与Forma ...

  5. FileInputStream 与 BufferedInputStream 效率对比

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3550158.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...

  6. java中多种写文件方式的效率对比实验

    一.实验背景 最近在考虑一个问题:“如果快速地向文件中写入数据”,java提供了多种文件写入的方式,效率上各有异同,基本上可以分为如下三大类:字节流输出.字符流输出.内存文件映射输出.前两种又可以分为 ...

  7. golang 浮点数 取精度的效率对比

    需求 浮点数取2位精度输出 实现 代码 package main import ( "time" "log" "strconv" " ...

  8. SIMD---SSE系列及效率对比

    SSE(即Streaming SIMD Extension),是对由MMX指令集引进的SIMD模型的扩展.我们知道MMX有两个明显的缺点: 只能操作整数. 不能与浮点数同时运行(MMX使用FPU寄存器 ...

  9. Snapman系统中TCC执行效率和C#执行效率对比

    Snapman集合了TCC编译器可以直接编译执行C语言脚本,其脚本执行效率和C#编译程序进行效率对比,包括下面4方面: 1.函数执行效率 2.数字转换成字符串 3.字符串的叠加 4.MD5算法 这是C ...

随机推荐

  1. Android(java)学习笔记135:Android中assets文件夹资源的访问

    Android资源文件分类: Android资源文件大致可以分为两种: 第一种是res目录下存放的可编译的资源文件: 这种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件 ...

  2. 关于Arrays类总结

    Arrays是java中的工具类,其中所有的方法都是static.类名就可以直接调用其中的方法. 本文部分引用自: http://www.importnew.com/8952.html Arrays. ...

  3. JSON对象和string的相互转换

    JSON.stringify(obj) 将JSON转为字符串. JSON.parse(string) 将字符串转为JSON格式.

  4. jQuery+php实现ajax文件即时上传

    很多项目中需要用到即时上传功能,比如,选择本地图片后,立即上传并显示图像.本文结合实例讲解如何使用jQuery和PHP实现Ajax即时上传文件的功能,用户只需选择本地图片确定后即实现上传,并显示上传进 ...

  5. Burosuite抓包Sqlmap学习Sql注入

    在sqlmap中加入--proyxy参数: --proxy "http://127.0.0.1:8080" 如下图所示: 回车以后sqlmap会自动抓到数据包: 我们选择向前(fo ...

  6. Singleton(单例模式)

    类的实例化次数只能一次. 例如:小王和小李通过门铃进行沟通,首先判断小王家是否有门,若没有建立门,若有门直接返回门. var xiaowang = (function(argument){ var m ...

  7. Python(2.7.6) glob - 匹配指定模式的文件

    Python 标准库的 glob 模块支持查询匹配指定模式的文件或目录.这里的模式使用的并不是正则表达式,而是通过通配符来匹配的 Unix 风格的路径名扩展. 支持的通配符: 通配符 说明 *  匹配 ...

  8. Beyond Compare 相同文件对比结果仍显示红色 解决方案

    转载:http://blog.sina.com.cn/s/blog_4d4bc1110100zj7x.html   1. 问题详细描述如下. 下图显示对比结果中,两侧的aaa.xml是一模一样,会话中 ...

  9. WCF编程系列(五)元数据

    WCF编程系列(五)元数据   示例一中我们使用了scvutil命令自动生成了服务的客户端代理类: svcutil http://localhost:8000/?wsdl /o:FirstServic ...

  10. ReactiveCocoa 谈谈concat

    今天的一个业务流程,业务流程大概就是这样的 1.从CoreData中获取之前的数据 2.更新界面 3.从网络获取数据 4.判断获取结果 5.处理错误判断 6.更新界面 7.判断结果numberOfNe ...