merge into 和 update 的效率对比
以前只考虑 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 的效率对比的更多相关文章
- PLSQL_性能优化系列17_Oracle Merge Into和Update更新效率
2015-05-21 Created By BaoXinjian 一.摘要 以前只考虑 merge into 只是在特定场合下方便才使用的,今天才发现,merge into 竟然会比 update 在 ...
- C#调用C++ memcpy实现各种参数类型的内存拷贝 VS marshal.copy的实现 效率对比
using System; using System.Runtime.InteropServices; using System.IO; namespace tx { struct ST { publ ...
- Merge into语句用法及其效率问题
Merge into语句用法及其效率问题 /*Merge into 详细介绍MERGE语句用来合并UPDATE和INSERT语句.通过MERGE语句,根据一张表或子查询的连接条件对另外一张表进行查询, ...
- string中Insert与Format效率对比、String与List中Contains与IndexOf的效率对比
关于string的效率,众所周知的恐怕是“+”和StringBuilder了,这些本文就不在赘述了.关于本文,请先回答以下问题(假设都是基于多次循环反复调用的情况下):1.使用Insert与Forma ...
- FileInputStream 与 BufferedInputStream 效率对比
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3550158.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...
- java中多种写文件方式的效率对比实验
一.实验背景 最近在考虑一个问题:“如果快速地向文件中写入数据”,java提供了多种文件写入的方式,效率上各有异同,基本上可以分为如下三大类:字节流输出.字符流输出.内存文件映射输出.前两种又可以分为 ...
- golang 浮点数 取精度的效率对比
需求 浮点数取2位精度输出 实现 代码 package main import ( "time" "log" "strconv" " ...
- SIMD---SSE系列及效率对比
SSE(即Streaming SIMD Extension),是对由MMX指令集引进的SIMD模型的扩展.我们知道MMX有两个明显的缺点: 只能操作整数. 不能与浮点数同时运行(MMX使用FPU寄存器 ...
- Snapman系统中TCC执行效率和C#执行效率对比
Snapman集合了TCC编译器可以直接编译执行C语言脚本,其脚本执行效率和C#编译程序进行效率对比,包括下面4方面: 1.函数执行效率 2.数字转换成字符串 3.字符串的叠加 4.MD5算法 这是C ...
随机推荐
- Android(java)学习笔记135:Android中assets文件夹资源的访问
Android资源文件分类: Android资源文件大致可以分为两种: 第一种是res目录下存放的可编译的资源文件: 这种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件 ...
- 关于Arrays类总结
Arrays是java中的工具类,其中所有的方法都是static.类名就可以直接调用其中的方法. 本文部分引用自: http://www.importnew.com/8952.html Arrays. ...
- JSON对象和string的相互转换
JSON.stringify(obj) 将JSON转为字符串. JSON.parse(string) 将字符串转为JSON格式.
- jQuery+php实现ajax文件即时上传
很多项目中需要用到即时上传功能,比如,选择本地图片后,立即上传并显示图像.本文结合实例讲解如何使用jQuery和PHP实现Ajax即时上传文件的功能,用户只需选择本地图片确定后即实现上传,并显示上传进 ...
- Burosuite抓包Sqlmap学习Sql注入
在sqlmap中加入--proyxy参数: --proxy "http://127.0.0.1:8080" 如下图所示: 回车以后sqlmap会自动抓到数据包: 我们选择向前(fo ...
- Singleton(单例模式)
类的实例化次数只能一次. 例如:小王和小李通过门铃进行沟通,首先判断小王家是否有门,若没有建立门,若有门直接返回门. var xiaowang = (function(argument){ var m ...
- Python(2.7.6) glob - 匹配指定模式的文件
Python 标准库的 glob 模块支持查询匹配指定模式的文件或目录.这里的模式使用的并不是正则表达式,而是通过通配符来匹配的 Unix 风格的路径名扩展. 支持的通配符: 通配符 说明 * 匹配 ...
- Beyond Compare 相同文件对比结果仍显示红色 解决方案
转载:http://blog.sina.com.cn/s/blog_4d4bc1110100zj7x.html 1. 问题详细描述如下. 下图显示对比结果中,两侧的aaa.xml是一模一样,会话中 ...
- WCF编程系列(五)元数据
WCF编程系列(五)元数据 示例一中我们使用了scvutil命令自动生成了服务的客户端代理类: svcutil http://localhost:8000/?wsdl /o:FirstServic ...
- ReactiveCocoa 谈谈concat
今天的一个业务流程,业务流程大概就是这样的 1.从CoreData中获取之前的数据 2.更新界面 3.从网络获取数据 4.判断获取结果 5.处理错误判断 6.更新界面 7.判断结果numberOfNe ...