利用Merge into 改写Update SQL 一例
前言
客户说,生产系统最近CPU使用率经常达到100%,请DBA帮忙调查一下。
根据客户提供的情况描述及对应时间段,我导出AWR,发现如下问题:
11v41vaj06pjd :每次执行消耗2,378,874.14 buffer 约等于18g 内存
bsfrz471nh9s4:每次执行消耗1,545,875.18 buffer 约等于12g 内存
非常大的内存消耗,而且执行频率高。
所以就断定这两条sql就是cpu使用率高的祸源,只要优化这两条sql,cpu必然而然的降下来。
优化前
这两条sql的结构是一样的,只是表连接有所不同,所以优化方法都是一致的。
update mm_writeoutstatus_to s
set s.status = '00'
where s.status = '0Z'
and s.id in (select distinct t.id
from mm_writeout_to t, mm_paymentin_events_td p
where exists (select 1
from mm_paymentin_events_td m,
mm_paymentin_events_td m1
where m.newno = 1420467997
and m.fatherno = m1.listno
and m1.sonno = p.listno)
and t.businessno = p.newno);
Execution Plan
----------------------------------------------------------
Plan hash value: 393324829
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | 21 | 4437 (1)| 00:00:54 |
| 1 | UPDATE | MM_WRITEOUTSTATUS_TO | | | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID | MM_WRITEOUTSTATUS_TO | 789 | 16569 | 96 (0)| 00:00:02 |
|* 4 | INDEX RANGE SCAN | IDX_WRITEOUTSTATUS_TEST | 789 | | 6 (0)| 00:00:01 |
| 5 | NESTED LOOPS | | 1 | 52 | 11 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 38 | 9 (0)| 00:00:01 |
| 7 | NESTED LOOPS | | 1 | 27 | 7 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID| MM_WRITEOUT_TO | 1 | 18 | 3 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_MM_WRITEOUT_TO | 1 | | 2 (0)| 00:00:01 |
|* 10 | TABLE ACCESS BY INDEX ROWID| MM_PAYMENTIN_EVENTS_TD | 1 | 9 | 4 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | IDX_PAYMENTINE_08 | 4 | | 2 (0)| 00:00:01 |
|* 12 | TABLE ACCESS BY INDEX ROWID | MM_PAYMENTIN_EVENTS_TD | 1 | 11 | 2 (0)| 00:00:01 |
|* 13 | INDEX UNIQUE SCAN | PK_MM_PAYMENTIN_EVENTS_TD | 1 | | 1 (0)| 00:00:01 |
|* 14 | TABLE ACCESS BY INDEX ROWID | MM_PAYMENTIN_EVENTS_TD | 1 | 14 | 2 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_MM_PAYMENTIN_EVENTS_TD | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter( EXISTS (SELECT 0 FROM "MM_PAYMENTIN_EVENTS_TD" "P","MM_WRITEOUT_TO"
"T","MM_PAYMENTIN_EVENTS_TD" "M1","MM_PAYMENTIN_EVENTS_TD" "M" WHERE "M"."NEWNO"=1420467997 AND
"M"."FATHERNO" IS NOT NULL AND "M"."FATHERNO"="M1"."LISTNO" AND "M1"."SONNO" IS NOT NULL AND
"T"."ID"=:B1 AND "M1"."SONNO"="P"."LISTNO" AND "P"."NEWNO"=TO_NUMBER("T"."BUSINESSNO")))
4 - access("S"."STATUS"='0Z')
9 - access("T"."ID"=:B1)
10 - filter("M"."FATHERNO" IS NOT NULL)
11 - access("M"."NEWNO"=1420467997)
12 - filter("M1"."SONNO" IS NOT NULL)
13 - access("M"."FATHERNO"="M1"."LISTNO")
14 - filter("P"."NEWNO"=TO_NUMBER("T"."BUSINESSNO"))
15 - access("M1"."SONNO"="P"."LISTNO")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1830312 consistent gets
154 physical reads
0 redo size
830 bytes sent via SQL*Net to client
1240 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
0 rows processed
分析
执行计划中有走filter关键字,且有两个子级,我们都知道,走这种连接方式是非常耗费性能的,主表返回多少行,被驱动表就得被扫描多少次。
利用merge into 可以等价改写update语句。
优化后
merge into mm_writeoutstatus_to s
using (select distinct t.id
from mm_writeout_to t, mm_paymentin_events_td p
where exists (select 1
from mm_paymentin_events_td m,
mm_paymentin_events_td m1
where m.newno = 1420467997
and m.fatherno = m1.listno
and m1.sonno = p.listno)
and t.businessno = p.newno)b
on (s.id = b.id)
when matched then
update set s.status = '00' where s.status = '0Z'
Execution Plan
----------------------------------------------------------
Plan hash value: 1386952490
------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 1 | 59 | 9822 (1)| 00:01:58 |
| 1 | MERGE | MM_WRITEOUTSTATUS_TO | | | | |
| 2 | VIEW | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID | MM_WRITEOUTSTATUS_TO | 1 | 53 | 3 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | 1 | 66 | 9822 (1)| 00:01:58 |
| 5 | VIEW | | 1 | 13 | 9819 (1)| 00:01:58 |
| 6 | SORT UNIQUE | | 1 | 52 | 9819 (1)| 00:01:58 |
|* 7 | HASH JOIN | | 1 | 52 | 9818 (1)| 00:01:58 |
| 8 | NESTED LOOPS | | 1 | 34 | 9 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | 1 | 20 | 7 (0)| 00:00:01 |
|* 10 | TABLE ACCESS BY INDEX ROWID| MM_PAYMENTIN_EVENTS_TD | 1 | 9 | 5 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | IDX_PAYMENTINE_08 | 4 | | 3 (0)| 00:00:01 |
|* 12 | TABLE ACCESS BY INDEX ROWID| MM_PAYMENTIN_EVENTS_TD | 1 | 11 | 2 (0)| 00:00:01 |
|* 13 | INDEX UNIQUE SCAN | PK_MM_PAYMENTIN_EVENTS_TD | 1 | | 1 (0)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | MM_PAYMENTIN_EVENTS_TD | 1 | 14 | 2 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_MM_PAYMENTIN_EVENTS_TD | 1 | | 1 (0)| 00:00:01 |
| 16 | TABLE ACCESS FULL | MM_WRITEOUT_TO | 1124K| 19M| 9797 (1)| 00:01:58 |
|* 17 | INDEX RANGE SCAN | IDX_WRITEOUTSTATUS_1 | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
7 - access("P"."NEWNO"=TO_NUMBER("T"."BUSINESSNO"))
10 - filter("M"."FATHERNO" IS NOT NULL)
11 - access("M"."NEWNO"=1420467997)
12 - filter("M1"."SONNO" IS NOT NULL)
13 - access("M"."FATHERNO"="M1"."LISTNO")
15 - access("M1"."SONNO"="P"."LISTNO")
17 - access("S"."ID"="B"."ID")
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
54083 consistent gets
0 physical reads
0 redo size
832 bytes sent via SQL*Net to client
1281 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
0 rows processed
------------------------------------------------------------------------------------------------------------------------------
优化前每次执行需要1830312 次逻辑读,优化后每次执行需要54083 次逻辑读,性能提升33.8倍
利用Merge into 改写Update SQL 一例的更多相关文章
- PLSQL_性能优化系列17_Oracle Merge Into和Update更新效率
2015-05-21 Created By BaoXinjian 一.摘要 以前只考虑 merge into 只是在特定场合下方便才使用的,今天才发现,merge into 竟然会比 update 在 ...
- merge into 和 update 的效率对比
以前只考虑 merge into 只是在特定场合下方便才使用的,今天才发现,merge into 竟然会比 update 在更新数据时有这么大的改进.其实呢,merge into部分的update和u ...
- UPDATE sql 优化
一个网友说他的存储过程中有一段update sql,运行了15分钟还没出结果,需要优化一下 他把sql发给我 UPDATE TB_RESULT R SET R.VOTE_COUNT=NVL(( SEL ...
- what a fuck postgre update sql
================= what a fuck postgre update sql ================= UPDATE temp_group_temp set group_ ...
- Could not execute JDBC batch update; SQL [delete from role where roleId=?]; constraint [null]; neste
今天在写多个删除功能的时候出现了这么一个错误:意思是删除操作的时候,没有找到对应的外键. Cannot delete or update a parent row: a foreign key con ...
- 利用闭包特性改写addEventListener的回调函数
var numClicks = 0; document.addEventListener("click",function(){ alert( ++numClicks); },fa ...
- MySql update inner join!MySql跨表更新 多表update sql语句?如何将select出来的部分数据update到另一个表里面?
项目中,评论数,关注数等数据,是实时更新的.+1,-1 这种. 有的时候,可能统计不准确. 需要写一个统计工具,更新校准下. 用Java写SQL和函数,代码很清晰,方便扩展,但是太慢了. 为了简单起见 ...
- C#备份及还原数据库的实现代码(粗略) // 利用C#还原数据库(SQL SERVER)备份文件到指定路径
C#数据库备份及还原 1.在用户的配置时,我们需要列出当前局域网内所有的数据库服务器,并且要列出指定服务器的所有数据库,实现代码如下: 取得数据库服务器列表: public ArrayList Get ...
- 大型面试现场:一条update sql执行都经历什么?
导读 Hi,大家好!我是白日梦!本文是MySQL专题的第 24 篇. 今天我要跟你分享的MySQL话题是:"从一条update sql执行都经历什么开始,发散开一系列的问题,看看你能抗到第几 ...
随机推荐
- Ruby Regexp类
正则表达(Regexp)类 更新:2017/06/18 改变[]集合的表格大小 80% ---> 100% 定义 正则表达: 和字符串匹配的模式(pattern)的写法 正则表达(Regexp ...
- jsonp处理跨域
什么是跨域? 简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即“同源策略”.而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果. 具体策略 ...
- bzoj 5277: [Usaco2018 Open]Out of Sorts【冒泡排序瞎搞】
首先考虑快排的递归什么时候停下,显然是当前段只剩下一个数了,也就是一个数两边出现分隔符 然后再考虑计算冒泡长度这个操作,因为有分割,所以我们可以把这些放到一起冒泡,这和递归每个区间冒泡是等价的 所以答 ...
- React 事件 传参
绑定事件用 bind方法,第一个参数是 this,第二个参数是需要传入的值如下: <a onClick={this.updateLabel.bind(this,'参数1','参数2')} > ...
- Hihocoder [Offer收割]编程练习赛70 解题报告 By cellur925
并没有第四题.(还不会矩阵乘法加速线性数列) 题目1 : 数位翻转 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个数 n,你可以进行若干次操作,每次操作可以翻转 ...
- [Usaco2006 Open]County Fair Events 参加节日庆祝
Description Farmer John has returned to the County Fair so he can attend the special events (concert ...
- poj 1511 Invitation Cards spfa 邻接矩阵
题目链接: http://poj.org/problem?id=1511 题目大意: 这道题目比较难理解,我读了好长时间,最后还是在队友的帮助下理解了题意,大意就是,以一为起点,求从一到其他各点的最短 ...
- 题解报告:hdu 1503 Advanced Fruits(LCS加强版)
Problem Description The company "21st Century Fruits" has specialized in creating new sort ...
- asp.net core连接sqlserver
开发环境:win7,vs2017,sqlserver2014 vs上建立一个asp.net core web项目和一个.net core的类库项目DBA 简单起见,在DBA项目中就一个类SqlServ ...
- synchronized(2)修饰方法之:普通方法
synchronized方法 [同一个对象的该方法一次只有一个线程可以访问,该对象的其它同步方法也被阻塞] 方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时, ...