以前只考虑 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. Setting up a database adapter

    Setting up a database adapter zend-db provides a general purpose database abstraction layer. At its ...

  2. ios 界面间跳转方法总结

    接触ios也有一段时间了,偶然间,我们公司的技术总监兼我的导师,问我,你可知道,界面间的跳转有几种方式?我说出了两种,但是也有点含糊其辞,于是我就想一定要找个时间总结一下.有句话说的好,“前人种树,后 ...

  3. GitHub帮助文档翻译1——helloWorld

    工欲善其事必先利其器 ,都不知道 GitHub到底是什么,还怎么玩?因为总是会读了第一句就忘了下一句,形成不了感觉,所以希望把读GitHub的帮助文档都翻译出来,总是看大段大段的东西,谁都会懵圈的.希 ...

  4. ubuntu系统安装flashplayer

    打开浏览器,输入adobe flashplayer 进入官方网站,下载Linux 32-bit, 简体中文, Firefox,下载.tar.gz包. 然后点击立即下载.下载之后找到解压该文件夹,找到 ...

  5. Jquery 1.11.1 Checkbox checked 判断

    if($(this).prop('checked'))

  6. Core Animation之CABasicAnimation

    在iOS中,图形可分为以下几个层次: 越上层,封装程度越高,动画实现越简洁越简单,但是自由度越低:反之亦然.本文着重介绍Core Animation层的基本动画实现方案. 在iOS中,展示动画可以类比 ...

  7. .net远程连接oracle数据库不用安装oracle客户端

    asp.net远程连接oracle数据库不用安装oracle客户端的方法下面是asp.net连接远程Oracle数据库服务器步骤: 1.asp.net连接oracle服务器需要添加Sytem.Data ...

  8. [译]Autoprefixer:用最可行的方式处理浏览器前缀的CSS后处理器

    Autoprefixer,通过Can I Use数据库来确定哪些浏览器前缀是需要的,然后解析CSS文件,将前缀添加到CSS规则里. 你所要做的就是添加你的资源构建工具(比如:Grunt),然后你就可以 ...

  9. Shell/Bash 变量/variable 循环/loop

    如何在bash脚本里面进行循环 #!/bin/bash n=9999 for(( i =1; i<=100;i++)) do /root/testProgram $n sleep 5 n=$(( ...

  10. C# 调用load事件

    在一个函数或者事件中调用另外的事件,例如调用Load事件 private void EventForm_Load(object sender, EventArgs e) { //相关内容 } priv ...