merge语句导致的CPU使用率过高的优化(二)

之前分享过一篇关于merge语句导致的CPU使用率过高优化的案例。的http://blog.itpub.net/23718752/viewspace-1819471/
后续的跟进没有补充,也“秀”一张图,红色的火焰是原来的系统负载,右边的部分是最近的逻辑读情况,不过惭愧的是,这个不是优化的效果,因为应用的高峰期已经处理完了,后面的sql调用频率极低,所以感觉不到任何的压力。所以通过这个图也可以看出,给一张差别巨大的图也不一定是系统优化的效果,也可能是其它外在因素。

那么既然要说跟进,后面的情节才够真实和现实,开发同学找到语句,修改花了些时间,今天突然联系到我,说已经修改完成了。我也从v$sql中抓取了几条语句,发现执行计划已经改变。
感觉这件事情就要告一段落,但是开发的同事过了一会找到我说,他们在应用端发现日志中出现了ORA-00001的错误。
### Cause: java.sql.SQLException: ORA-00001: unique constraint (AXXXX.OPENPLATFORM_USER) violated
这个问题着实在意料之外,他们反馈出现问题后,立即回退了代码,但是日志保留了下来,让我看看是什么问题。找开发要绑定变量的值,貌似还比较困难,那就算了,自己分析吧。
比如还是简单模拟这个错误。
CREATE TABLE TEST(ID NUMBER,NAME VARCHAR(100));
ALTER TABLE TEST MODIFY(ID UNIQUE);
INSERT INTO TEST VALUES(100,'BB_NOT_MATCHED');
INSERT INTO TEST VALUES(1000,'BBB_NOT_MATCHED');
SQL> select*from test;
        ID NAME
---------- --------------------
      1000 BB_NOT_MATCHED
       100 BBB_NOT_MATCHED
我们已经插入了两条值,这个时候来尝试一下,update是否生效
SQL> MERGE INTO TEST t
      USING (SELECT ID from TEST where ID=1000 union select -1 id from dual ) tw
      ON (tw.ID=T.ID)
      WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
      where ID= 1000
      WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(1000,'BBB_NOT_MATCHED') ;
MERGE INTO TEST t
*
ERROR at line 1:
ORA-00001: unique constraint (TEST.SYS_C0011234) violated
这个错误还是有些奇怪,本来预计的update变成了insert,结果还违反了唯一性约束。

来看看最初始版本的执行情况。
SQL> MERGE INTO TEST t
                       USING (SELECT count(*) CNT from TEST where ID=1000 ) tw
                       ON (tw.CNT>0)
                       WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED' where ID=1000
                       WHEN NOT MATCHED THEN INSERT(ID,NAME) VALUES(1000,'BBB_NOT_MATCHED');
1 row merged.
发现确实是做了update,把id=1000的行,name列修改成了AAA_MATCHED
SQL> select *from test;
        ID NAME
---------- --------------------
      1000 AAA_MATCHED
       100 BBB_NOT_MATCHED
手工把数据改回来,继续测试。
SQL> update test set name='BBB_NOT_MATCHED' where id=1000;
1 row updated.

SQL> select *from test;
        ID NAME
---------- --------------------
      1000 BBB_NOT_MATCHED
       100 BBB_NOT_MATCHED
这个时候开发的同学突然给我反馈说,他们看如果把union all的字句取消就不报错了。原来他们也在debug,我告诉他们,不报错不代表没错,还是需要搞明白最根本的原因。 
MERGE INTO TEST t
  USING (SELECT ID from TEST where ID=1000   ) tw
  ON (tw.ID=T.ID)
  WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
  where ID= 1000
  WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(1000,'BBB_NOT_MATCHED') ;  
SQL> select *from test;
        ID NAME
---------- --------------------
      1000 AAA_MATCHED
       100 BBB_NOT_MATCHED       
这个时候update确实能够正常执行,似乎也是预期的结果,那么做一条insert,看看效果。      
MERGE INTO TEST t
  USING (SELECT ID from TEST where ID=2000  ) tw
  ON (tw.ID=T.ID)
  WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
  where ID= 2000
  WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(2000,'BBB_NOT_MATCHED') ;      
0 rows merged.  
可以看到,id=2000的行没有插入数据。这个我觉得也就是为什么开发的同学没有选用这个方法的根本原因。但是似乎他们没有找到更好的方法,
那么继续改进,就是我上次分享的,加入union all的部分。
MERGE INTO TEST t
  USING (SELECT ID from TEST where ID=2000  union all select -999 from dual ) tw
  ON (tw.ID=T.ID)
  WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
  where ID= 2000
  WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(2000,'BBB_NOT_MATCHED') ;
1 row merged.
SQL> select *from test;
        ID NAME
---------- --------------------
      1000 AAA_MATCHED
       100 BBB_NOT_MATCHED
      2000 BBB_NOT_MATCHED
这个时候问题来了,insert可以了,但是update有问题了。
SQL> MERGE INTO TEST t
  2    USING (SELECT ID from TEST where ID=2000  union all select -999 from dual ) tw
  3    ON (tw.ID=T.ID )
  4    WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
  5    where ID= 2000
  6    WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(2000,'BBB_NOT_MATCHED') ;
MERGE INTO TEST t
*
ERROR at line 1:
ORA-00001: unique constraint (TEST.SYS_C0011234) violated
如果你看晕了,我来整理一下思路。
###加入union all的方案
不存在id=2000 可以insert
已存在id=2000 update 报ora-00001

### 去掉union all子句
不存在id=2000 可以插入
已存在id=2000 update无法执行
那么来一个动态的条件,可以不?
SQL> MERGE INTO TEST t
         USING (SELECT ID from TEST where ID=2000  union all select -999 from dual) tw
          ON (tw.ID=T.ID or tw.id=-999)
          WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
          where ID= 2000
          WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(2000,'BBB_NOT_MATCHED') ;
MERGE INTO TEST t
           *
ERROR at line 1:
ORA-30926: unable to get a stable set of rows in the source tables

所以这些思路都不同,但是根据id来决定Inert,update也算一个常规问题,吃完晚饭继续琢磨,总算找到了一个合适的方法。
SQL> MERGE INTO TEST t
              USING (SELECT 2000 id FROM dual ) tw
              ON (tw.ID=T.ID )
              WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
              where ID= 2000
              WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(2000,'BBB_NOT_MATCHED') ;
1 row merged.
这种情况下条件是唯一性匹配的,匹配与否就很清晰了。
当前数据情况如下:
SQL> select *from test;
        ID NAME
---------- --------------------
      1000 AAA_MATCHED
       100 BBB_NOT_MATCHED
      2000 AAA_MATCHED
插入一条新数据
SQL>  MERGE INTO TEST t
                  USING (SELECT 3000 id FROM dual ) tw
                  ON (tw.ID=T.ID )
                  WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
                  where ID= 3000
                  WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(3000,'BBB_NOT_MATCHED') ;
1 row merged.
SQL> select *from test where id=3000;
        ID NAME
---------- --------------------
      3000 BBB_NOT_MATCHED
更新一条记录
SQL>   MERGE INTO TEST t
                  USING (SELECT 3000 id FROM dual ) tw
                  ON (tw.ID=T.ID )
                  WHEN MATCHED THEN UPDATE SET t.NAME='AAA_MATCHED'
                  where ID= 3000
                  WHEN NOT MATCHED THEN INSERT(ID, NAME) VALUES(3000,'BBB_NOT_MATCHED') ;
SQL> select *from test where id=3000;
        ID NAME
---------- --------------------
      3000 AAA_MATCHED
改进后的执行计划如下:
Execution Plan
----------------------------------------------------------
Plan hash value: 3869333021
-----------------------------------------------------------------------------------------------
| Id  | Operation                      | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | MERGE STATEMENT                |              |     1 |    78 |     3   (0)| 00:00:01 |
|   1 |  MERGE                         | TEST         |       |       |            |          |
|   2 |   VIEW                         |              |       |       |            |          |
|   3 |    NESTED LOOPS OUTER          |              |     1 |    79 |     3   (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL          | DUAL         |     1 |     2 |     2   (0)| 00:00:01 |
|   5 |     TABLE ACCESS BY INDEX ROWID| TEST         |     1 |    77 |     1   (0)| 00:00:01 |
|*  6 |      INDEX UNIQUE SCAN         | SYS_C0011234 |     1 |       |     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   6 - access("T"."ID"(+)=CASE  WHEN (ROWID IS NOT NULL) THEN 3000 ELSE 3000 END )
1 row merged.
所以正式环境的语句也是类似的思路。
MERGE INTO UC_OPENPLATFORM_USER t
                   USING (SELECT :1 USER_ID,:2 PLATFORM from DUAL ) tw
                   ON (tw.USER_ID=T.USER_ID and tw.PLATFORM=t.PLATFORM)
                   WHEN MATCHED THEN UPDATE SET t.NAME=:3, t.UPDATE_DATE=SYSDATE
where USER_ID=:4 and PLATFORM=:5
                   WHEN NOT MATCHED THEN INSERT(USER_ID, PLATFORM, NAME,
CREATE_DATE, UPDATE_DATE) VALUES(:6, :7, :8, SYSDATE, SYSDATE)             
改动之后还是需要再部署测试,相信大体就没有问题了。
通过这个案例可以发现,很多优化的时候从执行计划等情况确实有了很大的提升,一些瓶颈也得到了解决,但是还是要更周密的测试,别修复了一个错,引来更多的问题。而且sql上线也要评估,进行验收测试。尽可能把问题都解决在沟通层面,不用那么多的邮件来标注,说明。

时间: 2024-11-10 00:07:40

merge语句导致的CPU使用率过高的优化(二)的相关文章

merge语句导致的CPU使用率过高的优化

今天有一个数据库有点反常,早上的时候报出了CPU使用率的警告. 警告内容如下: ZABBIX-监控系统: ------------------------------------报警内容: CPU utilization is too high ------------------------------------报警级别: PROBLEM ------------------------------------监控项目: CPU idle time:44.61 % -------------

电脑CPU温度过高 cpu使用率较高怎么办

cpu使用率高是网民经常遇到的问题,CPU使用率高其实就是你运行的程序占用的CPU资源,说明你的机器在这个时间上运行了很多程序.长期使用会让CPU长时间处于高热状态会对影响cpu寿命产生点影响,CPU使用率过高怎么办呢? cpu使用率高的原因和解决办法: 一.电脑正在运行大型的应用程序,例如大型的处理软件.3D网络游戏等等1.退出当前大型程序,等待cpu使用率恢复正常. 2.查看电脑配置是否满足运行该程序的最低配置,如果确实是电脑配置不行的话,那么就建议网友将电脑硬件进行升级了. 3.如果是软件

电脑CPU使用率过高怎么办?

  cpu使用率高是网民经常遇到的问题,CPU使用率高其实就是你运行的程序占用的CPU资源,说明你的机器在这个时间上运行了很多程序.长期使用会让CPU长时间处于高热状态会对影响cpu寿命产生点影响,CPU使用率过高怎么办呢?首先我们来看看使cpu使用率高的原因,好对症下药. cpu使用率高的原因和解决办法: 一.电脑正在运行大型的应用程序,例如大型的处理软件.3D网络游戏等等 1.退出当前大型程序,等待cpu使用率恢复正常. 2.查看电脑配置是否满足运行该程序的最低配置,如果确实是电脑配置不行的

cpu使用率过高怎么解决

  cpu使用率过高怎么解决 CPU使用率过高是什么原因 1.电脑运行了大型的程序,例如大型的游戏,3D网络游戏等等,这种情况通常是正常的,这类程序需要较多的CPU资源,网友将大型的程序退出一段时间,CPU使用率基本上就恢复正常了; 2.电脑如果中毒,例如下载者类的病毒,这类病毒会在后台下载大量的恶意程序运行,试想一下,电脑突然运行了几十个程序,CPU使用率必然会突然飙升,用户会觉得很卡.这种情况就需要大家下载杀毒软件或者木马专杀工具进行扫描,清除完病毒.木马之后CPU使用率就会降低了; 3.C

如何解决cpu使用率过高的问题

  CPU使用率是什么? CPU使用率其实就是你运行的程序占用的CPU资源,表示你的机器在某个时间点的运行程序的情况.使用率越高,说明你的机器在这个时间上运行了很多程序,反之较少.使用率的高低与你的CPU强弱有直接关系. CPU使用率过高是什么原因? 可能原因1.电脑运行了大型的程序,例如大型的游戏,3D网络游戏等等,这种情况通常是正常的,这类程序需要较多的CPU资源,网友将大型的程序退出一段时间,CPU使用率基本上就恢复正常了; 可能原因2.电脑如果中毒,例如下载者类的病毒,这类病毒会在后台下

cpu使用率忽高忽低怎么办?

  首先我们打开任务管理器,然后切换到cpu行列,对占用cpu的出程序逐一排查,查看哪个cpu程序占用的cpu忽高忽低的情况.找到占用cpu不稳定的进程将其结束掉(不是系统进程的前提下),如果发现时系统进程不能结束的话,那就系统的问题了. 系统的问题包括驱动安装不正常,或者系统被病毒木马入侵的情况,还有一种情况就是杀毒软件对电脑的监控占用大量的cpu导致不稳定的情况. 解决方法:先用杀毒软件杀下毒,最好是重新安装一个正版系统,这样就不会出现系统导致占用cpu使用率不稳定的情况.然后在减少开机启动

Win7系统CPU使用率忽高忽低怎么办?

  步骤如下: 1.首先要明白在哪里查看CPU使用率,我们右键桌面的底部工具栏,然后选择启动任务管理器. 2.在弹出的Windows任务管理器选项卡中选择性能选项,在这里就可以查看电脑的CPU使用情况了. 3.然后我们看到电脑的CPU使用率忽高忽低或者偏高了,这种情况十有八九是开了某个占CPU的软件,但是通常我们也确定不了哪个软件占CPU,不是说软件体积越大就越占CPU,不是这样的. 4.我们点击性能项目右下角的资源监视器,如下图. 5.在资源监视器选项卡下我们可以看到很直观地观察到哪个软件最占

bash脚本-阿里云CPU使用率偏高,由于某个守护进程,求现象解释

问题描述 阿里云CPU使用率偏高,由于某个守护进程,求现象解释 昨天发现我阿里云的cpu莫名偏高,参见提问问了阿里云的技术支持,木有回答到点上,他们说是内存太高,但是我开了swap分区之后,也没有见到cpu使用率降低. 经过测试,发现,这个现象适合我写的一个进程守护脚本相关,谁能解释一下?脚本如下:#!/bin/bash while truedo process=ps -ef|grep /opt/tomcat7|grep -v grep if [ -z ""${process}&quo

merge语句导致的性能问题紧急优化

晚上正在休息的时候,突然收到一封报警邮件. 报警内容: CPU utilization is too high ------------------------------------ 报警级别: PROBLEM ------------------------------------ 监控项目: CPU idle time:59.11 % ------------------------------------ 这个报警信息已经非常明确,CPU使用率很紧张了.这台服务器上运行着Oracle和M