zoukankan      html  css  js  c++  java
  • 优化更新语句中的标量子查询

    数据库环境: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

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

    现在我们回到开始的案例,我把更新语句改成查询的了,然后执行。总共查询出476056条记录,耗时30s。

    SELECT  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 = '200710000335'
                     ), 0)
    FROM    fapply_04
    /*分别统计fapply_04,fexp_03的数据*/
    SELECT  COUNT(*)
    FROM    fexp_03
    WHERE   fexp_03.feetype_flag = ''
            AND fexp_03.fexp_no = '200710000335'--3
    SELECT  COUNT(*)
    FROM    fapply_04--476056

    然后,把SQL改写成内联接的方式,我们再来看一下执行情况。查询1条数据,耗时0s。

    SELECT  conf_y_fee_amt = ISNULL(fapply_04.conf_y_fee_amt, 0)
            + ISNULL(fexp_03.opr_amt, 0)
    FROM    fapply_04
            INNER JOIN ( SELECT com_id ,
                                origin_no ,
                                origin_line_no ,
                                SUM(fexp_03.opr_amt) opr_amt
                         FROM   fexp_03
                         WHERE  fexp_03.feetype_flag = ''
                                AND fexp_03.fexp_no = '200710000335'
                         GROUP BY com_id ,
                                origin_no ,
                                origin_line_no
                       ) fexp_03 ON 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
    /*分别统计fapply_04,fexp_03的数据*/
    SELECT  COUNT(*)
    FROM    fexp_03
    WHERE   fexp_03.feetype_flag = ''
            AND fexp_03.fexp_no = '200710000335'--3
    
    SELECT  COUNT(*)
    FROM    fapply_04--476056

    综上,根据业务的意思,原本只需更新一条记录的,由于使用子查询,做了全表更新。

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

    (本文完)

  • 相关阅读:
    Unique path
    *Jump Game
    Valid Palindrome
    *Reverse Words in a String
    Min Stack
    [?]*Simplify Path
    *Valid Parentheses
    *Sqrt(x)
    String to Integer (atoi)
    Add Digits
  • 原文地址:https://www.cnblogs.com/boss-he/p/4547425.html
Copyright © 2011-2022 走看看