遇到性能问题的sql如下:
sql1:
UPDATE amlclientlevel a
SET    a.client_value = (SELECT l.client_value
                         FROM   amlclientdynamiclevel l
                         WHERE  l.inner_client_id = a.inner_client_id)
WHERE  a.client_value = 0
       AND a.need_value = '0'
       AND a.client_status = '0'
       AND EXISTS (SELECT 1
                   FROM   amlclientdynamiclevel l
                   WHERE  l.inner_client_id = a.inner_client_id);
此sql执行超过两个小时跑不出结果。两张表都是几百兆大小的小表,按照常理小表不应该产生性能问题。
 
执行计划1:
 

amlclientlevel 表上的索引

amlclientdynamiclevel 表上的索引
 

问题发生的原因有两点
 
第一点:上诉update的写法会导致amlclientlevel和amlclientdynamiclevel在两个地方产生关联,一处是EXISTS一处是set。
SET  a.client_value = (SELECT l.client_value
                         FROM   amlclientdynamiclevel l
                         WHERE  l.inner_client_id = a.inner_client_id)
这样的set写法执行的过程其实是类比标量子查询的执行过程。对应update的每一个返回行都需要。
 
小知识点:
8 - filter(NVL("L"."INNER_CLIENT_ID",' ')=:B1)
sql本身没有绑定变量,在执行计划中 出现绑定变量值,应该是执行计划中出现了传值。应该留意这样的情况,传值可能导致严重的性能问题。
 
 
第二点:生成index hash join VIEW 。本身这样的执行步骤效率不高,结合set 引用的类比标量子查询的更新方式,导致数万次的index hash join VIEW生成及过滤数据成了整个sql的瓶颈。
 
执行计划2:

 
解决思路其实也是两点
第一点:改善set写法让其不再发生类比标量子查询的执行过程,减少一个关联。改写update为merge into的写法。
sql2:
MERGE /*+  GATHER_PLAN_STATISTICS J1 */ INTO AMLCLIENTLEVEL_BAK A
   USING AMLCLIENTDYNAMICLEVEL_BAK L
                         ON (L.INNER_CLIENT_ID = A.INNER_CLIENT_ID)
WHEN MATCHED THEN
UPDATE  SET A.CLIENT_VALUE = L.CLIENT_VALUE
WHERE A.CLIENT_VALUE = 0
   AND A.NEED_VALUE = '0'
   AND A.CLIENT_STATUS = '0';
 
执行计划3:
 
优化后的执行效率为13s。上面的执行计划缺少有效的数据过滤后再进行两表关联。
 
尝试改写merge让其先进行数据过滤
sql3:
MERGE /*+ GATHER_PLAN_STATISTICS J1 */ INTO (select * from AMLCLIENTLEVEL_BAK A WHERE A.CLIENT_VALUE = 0
   AND A.NEED_VALUE = '0'
   AND A.CLIENT_STATUS = '0') A
   USING AMLCLIENTDYNAMICLEVEL_BAK L
                         ON (L.INNER_CLIENT_ID = A.INNER_CLIENT_ID)
WHEN MATCHED THEN
UPDATE  SET A.CLIENT_VALUE = L.CLIENT_VALUE;
本次改写未起到先进行数据过滤作用,oracle内部选取的执行计划依旧是执行计划3。
 
实际上在表上添加了两个有效的索引后,sql3的执行计划(执行计划4)才是先进行数据过滤,效率已经提高。
create index AMLCLIENTLEVEL_BAK_IDX01 on AMLCLIENTLEVEL_BAK (CLIENT_VALUE, NEED_VALUE);
create index AMLCLIENTDYNAMICLEVEL_B_IDX1 on AMLCLIENTDYNAMICLEVEL_BAK (INNER_CLIENT_ID, CLIENT_VALUE);
 
执行计划4:
 

小知识点:
ON (L.INNER_CLIENT_ID = A.INNER_CLIENT_ID and  A.CLIENT_VALUE = 0
   AND A.NEED_VALUE = '0'
   AND A.CLIENT_STATUS = '0')
SET中的字段不能出现在ON的关联条件中
 
第二点:优化index hash join VIEW,建立有效的索引,引导正确的sql的执行计划。
 
create index AMLCLIENTLEVEL_BAK_IDX01 on AMLCLIENTLEVEL_BAK (CLIENT_VALUE, NEED_VALUE);
create index AMLCLIENTDYNAMICLEVEL_B_IDX1 on AMLCLIENTDYNAMICLEVEL_BAK (INNER_CLIENT_ID, CLIENT_VALUE);
 
尝试建议索引不进行sql改写后的执行效率也是很高的。
执行计划5:

 
既然这样还有必要改写sql吗?
1、首先建立索引是比较危险的,可能导致其他sql出现性能问题,正确的方式是需要测试验证后决定。
2、针对不同业务系统数据处理情况决定,本次案例中数据量小,展示不出update和merge性能上的巨大差距。
3、如果数据量非常大,可能既需要sql改写又需要添加有效的索引。
 
 

一条update语句优化小记的更多相关文章

  1. sql执行万条update语句优化

    几个月没有更新笔记了,最近遇到一个坑爹的问题,顺道记录一下.. 需求是这样的:一次性修改上万条数据库. 项目是用MVC+linq的. 本来想着用 直接where() 1 var latentCusto ...

  2. 完蛋,公司被一条 update 语句干趴了!

    大家好,我是小林. 昨晚在群划水的时候,看到有位读者说了这么一件事. 在这里插入图片描述 大概就是,在线上执行一条 update 语句修改数据库数据的时候,where 条件没有带上索引,导致业务直接崩 ...

  3. 如何将多条update语句合并为一条

    需求: 如何将多条update语句合并为一条update语句:如,update table1 set col='2012' where id='2014001'      update table1  ...

  4. 一条update语句到底加了多少锁?带你深入理解底层原理

    迎面走来了你的面试官,身穿格子衫,挺着啤酒肚,发际线严重后移的中年男子. 手拿泡着枸杞的保温杯,胳膊夹着MacBook,MacBook上还贴着公司标语:"我爱加班". 面试开始,直 ...

  5. Oracle的update语句优化研究

    最近研究sql优化,以下文章转自互联网: 1.     语法 单表:UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 如:update t_join_situation s ...

  6. MySQL45讲:一条update语句是怎样执行的

    首先创建一张表: create table T(ID int primary key,c int); 如果要更新ID=2这行+1:应该这样写 update T set c=c+1 where ID=2 ...

  7. [转]Oracle的update语句优化研究

    原文地址:http://blog.csdn.net/u011721927/article/details/39228001 一.         update语句的语法与原理 1.     语法 单表 ...

  8. Sql Server执行一条Update语句很慢,插入数据失败

    今天同事要我修改服务器数据库里面的2条数据,查看服务器上的SQL Server数据库的时候,发现这几天数据没有添加成功,然后发现磁盘很快就满了,执行Update语句时,执行半天都提示还在执行,查询语句 ...

  9. 用一条UPDATE语句交换两列的值

    在SQL UPDATE语句中,"="右侧的值在整个UPDATE语句中都是一致的,所有更新同时发生!因此以下语句将在没有临时变量的情况下交换两列的值: UPDATE table SE ...

随机推荐

  1. 转:深度学习与自然语言处理之五:从RNN到LSTM

    原文地址:http://blog.csdn.net/malefactor/article/details/50436735/ 大纲如下: 1.RNN 2.LSTM 3.GRN 4.Attention ...

  2. 什么是位、字节、字、KB、MB?

    1. 位(bit)是计算机里最小的数据单位,每一位的状态只能是0或者1 2. 字节(Byte)      1Byte = 8 bit      它是存储空间的基本计量单位,1byte可以存储一个英文字 ...

  3. Codeforces731D 80-th Level Archeology

    考虑将两个单词变成有序,我们可以得到一个或者两个旋转次数的区间. 然后考虑将两组单词变成有序,比如[l,mid]和[mid+1,r],对于mid和mid+1这两个单词我们可以求出使他们有序的旋转次数的 ...

  4. SpringBoot整合Spring Data Solr

    此文不讲solr相关,只讲整合,内容清单如下 1. maven依赖坐标 2. application.properties配置 3. Java Config配置 1. maven坐标 <depe ...

  5. android 浏览器对图片加载高度渲染问题

    今天在开发有道汉语词典移动版的时候遇到了一个很奇怪的问题. 在android设备上访问的时候,总是发现有底部背景色不能完全渲染出来的情况(有时候又是正常的,一会儿出现一会儿不出现,iphone设备也是 ...

  6. HDU2586(tarjanLCA板子)

    ; int T, n, m; int f[maxn], vis[maxn], dis[maxn], ans[maxn]; vector<P> vc[maxn]; vector<int ...

  7. HDOJ 5475 An easy problem

    题目传送门 题意:一个计算器,两种操作,乘上x,或者除掉之前的某个x,结果取模输出 分析:因为取模不支持除法,然后比赛时想到用逆元,结果发现MOD需要与b互质,结果一直苦苦寻找求逆元的其它方法.后来队 ...

  8. Contextual Action bar(3) 两个示例

    一.通过activity启动Context Action Bar 1.主java public class ActivityActionModeFrgmt extends Fragment imple ...

  9. 136 Single Number 数组中除一个数外其他数都出现两次,找出只出现一次的数

    给定一个整数数组,除了某个元素外其余元素均出现两次.请找出这个只出现一次的元素.备注:你的算法应该是一个线性时间复杂度. 你可以不用额外空间来实现它吗? 详见:https://leetcode.com ...

  10. FACVSPOW - Factorial vs Power 数学方法 + 二分

    http://www.spoj.com/problems/FACVSPOW/ 求解n! > a^n最小的整数n 对于有n!和a^n的东西,一般是取ln 然后就是求解 (ln(1) + ln(2) ...