利用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执行都经历什么开始,发散开一系列的问题,看看你能抗到第几 ...
随机推荐
- 【WIP】外汇与证券交易29个技术指标
创建: 2017/05/16 更新: 2017/05/30 更新: 2017/10/14 标题加上[WIP],增加创建时间 指标名称 函数原型(prototype) 参考与分析 (refer ...
- Ruby Regexp类
正则表达(Regexp)类 更新:2017/06/18 改变[]集合的表格大小 80% ---> 100% 定义 正则表达: 和字符串匹配的模式(pattern)的写法 正则表达(Regexp ...
- bzoj 3824: [Usaco2014 Dec]Guard Mark【状压dp】
设f[s]为已经从上到下叠了状态为s的牛的最大稳定度,转移的话枚举没有在集合里并且强壮度>=当前集合牛重量和的用min(f[s],当前放进去的牛还能承受多种)来更新,高度的话直接看是否有合法集合 ...
- .Net Core之Configuration
ASP.NET CORE 中自动集成了应用配置,支持从以下 源 处获取配置键值对 命令行 环境变量 内存 文件配置 其中文件配置是我们最常用的方式,默认文件是.json的json格式文件,摒弃了以往. ...
- 【SQL】从待选项中随机选一个
由于SQL Server没有数组类型,所以在面对“从若干待选项中选一个”这种需求时,往往要采取变通办法,比如弄个‘a|b|c’这样的字符串然后对字符串进行处理:又或者把待选项塞进一个临时表,然后把问题 ...
- USACO Training3.3 A Game【区间Dp】 By cellur925
题目传送门 一股浓浓的博弈论香气...然而本蒟并不会博弈论. 开始用双端队列+假的dp水过了24pts水数据. 其实是布星的,两人都绝顶聪明会深谋远虑不像我只看眼前,所以上述算法错误. 正解:区间dp ...
- Luogu P3916 图的遍历 【优雅的dfs】【内有待填坑】By cellur925
说明 • 对于60% 的数据, n,m在1e3内 • 对于100% 的数据, n,m在1e5内. 本弱弱上来就是一顿暴搜打,dfs n次,每次更新答案,复杂度为O(n*n),果然TLE,60分抱回家. ...
- not and or
not and or (逻辑表达式) 首先要做一些准备知识: 1,优先级:逻辑型 < 测试型 < 关系型 < 算数型 2,逻辑型优先级:or < and < not 3, ...
- DFS Codeforces Round #299 (Div. 2) B. Tavas and SaDDas
题目传送门 /* DFS:按照长度来DFS,最后排序 */ #include <cstdio> #include <algorithm> #include <cstrin ...
- 题解报告:hdu1205吃糖果(插空法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1205 Problem Description HOHO,终于从Speakless手上赢走了所有的糖果, ...