优化更新语句中的标量子查询

数据库环境:SQL SERVER 2008R2

今天看到开发写的一条更新语句,第一眼是觉得这个SQL的业务有问题,再细看子查询部分,才意识到这是开发人员使的“怪招”。

这个SQL能满足业务的需要,只是开发人员在写这个SQL的时候应该不会考虑到存在性能问题。具体SQL如下:

UPDATE  fapply_04
SET     conf_y_fee_amt = ISNULL(conf_y_fee_amt, 0)
        + ISNULL(( SELECT   SUM(fexp_03.opr_amt)
                   FROM     fexp_03
                   WHERE    fexp_03.com_id = fapply_04.com_id
                            AND fexp_03.origin_no = fapply_04.fapply_no
                            AND fexp_03.origin_line_no = fapply_04.line_no
                            AND fexp_03.feetype_flag = ‘‘
                            AND fexp_03.fexp_no = :fexp_no
                 ), 0)

开发人员原本想把fexp_03表中的opr_amt累加到对应记录的fapply_04表的conf_y_fee_amt字段上,但是,这条SQL实际上

把fapply_04整张表都更新了(没有对应记录则累加0)。

现在我们来做个实验,验证一下我的说法

1.数据准备

创建2张表,分别是表a和表b,脚本脚本如下:

--创建a表
SELECT * INTO a FROM
(
SELECT 1 AS id,10 AS score
UNION ALL
SELECT 2 AS id,20 AS score
UNION ALL
SELECT 3 AS id,30 AS score
UNION ALL
SELECT 4 AS id,40 AS score) t
--创建b表
SELECT * INTO b FROM(
SELECT 2 AS id,-20 AS cn) t

2.更新数据

如果a表和b表的id匹配,则累加b表对应的cn字段的数据,否则,减5。

UPDATE  a
SET     score = score + ISNULL(( SELECT cn
                                 FROM   b
                                 WHERE  b.id = a.id
                               ), -5)
SELECT  *
FROM    a

好,我们现在来对比一下更新前后,a表数据的变化。左图是更新前,右图是更新后。

     

看到没,是不是a表发生了全表更新呢?

全表更新把不必要的记录也更新了,数据量大的时候,会造成不必要的影响。

那怎么避免这个问题呢?

把子查询改成内连接即可,看脚本

UPDATE  a
SET     a.score = a.score + b.cn
FROM    a
        INNER JOIN b ON a.id = b.id
SELECT  *
FROM    a

再贴上结果图,对比前面的子查询更新的图,是不是用内连接只更新了条件匹配的记录?

小结一下,有些时候,我们光是把SQL实现了还不够,还要考虑我们的代码会不会造成性能问题,再多想想可能的实现方法。

(本文完)

时间: 2024-08-06 00:40:40

优化更新语句中的标量子查询的相关文章

Oracle sql优化之分析函数优化标量子查询

待优化语句如下 select a.code as code, a.m_code as m_code,a.stktype as f_stype,a.e_year as e_year, b.sname as sname,a.c_date as c_date,to_char(sysdate,'YYYYMMDD') as createtime, to_char(sysdate,'YYYYMMDD') as updatetime, (select sum(valuef2) from a t where t

警惕 MySql 更新 sql 的 WHERE 从句中的 IN() 子查询时出现的性能陷阱

警惕 MySql 更新 sql 的 WHERE 从句中的 IN() 子查询时出现的性能陷阱 以下文章来源:https://blog.csdn.net/defonds/article/details/46745143 mer_stage 表有 216423 条记录,DDL:CREATE TABLE `mer_stage` ( `STAGE_ID` int(11) NOT NULL AUTO_INCREMENT, `MER_ID` int(11) NOT NULL, `MER_CODE` varch

SQL Server的优化器会缓存标量子查询结果集吗

在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减少SQL对函数(Function)的调用次数, ORACLE会在内存中构建一个哈希表来缓存标量子查询的结果. 那么SQL Server的优化器是否也会有类似这样的功能呢? 抱着这样的疑问,动手测试了一下,准备测试环境 CREATE TABLE TEST (    ID  INT );     DECLARE

优化有标量子查询的SQL

数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_year , LEFT(saft04.dept_id, 4) sdept_id , saft04.vdept_id , saft04.dept_id , saft04.fee_id , saft04.vitem_id , ISNULL(saft04.fee_amt, 0) AS saft04_fee_

标量子查询

--标量子查询select e.empno, e.ename, e.sal, e.deptno,       (select d.dname from dept d where e.deptno = d.deptno)as dname  from emp e--插入一条数据insert into emp(empno,deptno) values(9999,null)--返回结果15条记录--改成left join(hash outer)select e.empno, e.ename, e.sal

SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

原文:SQL点滴10-使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比 今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了.我从简单到复杂地写,希望高手们不要见笑.下面的sql语句设计到三个表,表的内容我用txt文件复制进去,这里不妨使用上一个随笔介绍的建立端到端的package的方法将这些表导入到数据库中,具体的就不说了. 从这里下载文件employ

DML语句(七) -- 子查询

一.含义 嵌套在其他语句内部的 select 语句称为子查询或内查询, 外面的语句可以是 insert.update.delete.select 等,一般 select 作为外面语句较多 外面如果为 select 语句,则此语句称为2外查询或主查询 二.分类 1.按出现位置 select 后面 仅仅支持标量子查询 from后面 表子查询 where 或 having 后面 标量子查询 列子查询 行子查询 exists 后面(结果不重要,判断是否有值) 标量子查询 列子查询 行子查询 表子查询 2

彻底搞懂oracle的标量子查询

oracle标量子查询和自定义函数有时用起来比较方便,而且开发人员也经常使用,数据量小还无所谓,数据量大,往往存在性能问题. 以下测试帮助大家彻底搞懂标量子查询. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values (1,'a1'); 1

oracle标量子查询

SQL> conn scott/scott Connected. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values(1,'a1'); 1 row created. SQL> insert into a values(2,'a2