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 ...
随机推荐
- ajax_for example
asp.net mvc 使用Ajax调用Action 返回数据. 使用asp.net mvc 调用Action方法很简单. 一.无参数方法. 1.首先,引入jquery-1.5.1.min.js ...
- c++中静态成员变量 静态成员函数 全局变量与静态函数的关系 字符串中括号的匹配编程 (笔试经历)
笔试经历 1 类中的静态变量不能通过构造函数参数列表来初始化,因为静态变量不属于哪个对象.同时静态变量在不初始化的情况下系统会自动为变量赋值,数值型赋值为零,字符型赋值为空. 非静态变量只有在定义时才 ...
- Linux学习之路:shell变量(二)环境变量
1.env (environment 的缩写)和export显示所有环境变量 2. 环境变量说明 环境变量 意义 HOME 用户主文件夹相当于“~” SHELL Linux默认为/bin/bash H ...
- 使用urllib进行网页爬取
# coding=gbk # 抓取开奖号码 # url:http://datachart.500.com/dlt/zoushi/jbzs_foreback.shtml ''' 对网页逐行迭代,找到目标 ...
- 封装JDBC操作数据库的方法
自己动手封装java操作数据库的方法: 一:目录结构 二:所需依赖的第三方jar包 这里只需引入mysql-connector-java-5.1.8-bin.jar,mysql数据库驱动jar包 三: ...
- Visual Studio dte 获取代码方法注释
- 并发容器之CopyOnWriteArrayList(转载)
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- monkey检测内存泄漏
monkey中检查内存泄漏,实际上是对一个操作多次操作后看内存情况,内存泄漏具体的原理可百度,现在我们梳理检测内存泄漏的方法: 测试前你需要安装: 1.MAT分析工具 2.使用工具事实监控内存指标,现 ...
- 使用blktrace排查iowait cpu高的问题
本文转自这里,blktrace在这种情况下的使用方法值得借鉴学习. ------------------------------------------------------------------ ...
- Activiti初学者教程
http://wenku.baidu.com/view/bb7364ad4693daef5ff73d32.html 1. 初识Activiti 1.1. 工作流与工作流引擎 工作流(workflow) ...