数据库环境: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_amt ,
ISNULL(saft04.fee_qty, 0) AS saft04_fee_qty ,
ISNULL(saft04.fee_amt_flex, 0) AS saft04_fee_amt_flex ,
ISNULL(saft04.adj_amt, 0) AS saft04_adj_amt ,
ISNULL(saft04.init_amt, 0) AS saft04_init_amt ,
ISNULL(saft04.flex_amt, 0) AS saft04_flex_amt ,
ISNULL(saft04.conf_fee_amt, 0) AS saft04_conf_fee_amt ,
saft04.fc_app_no ,
saft04.zone_id ,
saft04.corr_id ,
CASE WHEN saft04.fc_app_no < ''
THEN ( CASE WHEN saft04.flexfapp_flag = 'Y'
THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
- ISNULL(conf_fee_amt, 0)
ELSE ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
+ ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
END )
ELSE CASE WHEN b.fee_type2 = ''
OR b.fee_type2 = ''
THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
- ISNULL(conf_fee_amt, 0)
WHEN b.fee_type2 = ''
THEN ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
+ ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
END
END bal_amt ,
ISNULL(( SELECT SUM(b.opr_amt)
FROM v_saft04_fexp b
WHERE b.fcapp_id = saft04.fc_app_no
), 0) AS qty1 ,
CASE WHEN b.fee_type2 = ''
OR b.fee_type2 = ''
THEN ISNULL(saft04.conf_fee_amt, 0)
- ( ISNULL(( SELECT SUM(b.opr_amt)
FROM v_saft04_fexp b
WHERE b.fcapp_id = saft04.fc_app_no
), 0) )
WHEN b.fee_type2 = ''
THEN ISNULL(saft04.init_amt, 0) + ISNULL(saft04.flex_amt, 0)
- ISNULL(( SELECT SUM(b.opr_amt)
FROM v_saft04_fexp b
WHERE b.fcapp_id = saft04.fc_app_no
), 0)
+ ISNULL(( SELECT SUM(d.opr_amt)
FROM v_fadj_rd d
WHERE d.fcapp_id = saft04.fc_app_no
), 0)
END qty2 ,
c.base_data2
FROM saft04
LEFT JOIN v_ctlm60 b ON b.fee_id = saft04.fee_id
LEFT JOIN ctlm1000 c ON c.d_type = 'fee_type2'
AND b.fee_type2 = c.base_data1
WHERE 1 = 1
AND saft04.com_id = 'LQPJ'
AND saft04.cur_year = 2015
AND saft04.dept_id LIKE '2001%'
AND ( saft04.dept_id IN ( SELECT dept_id
FROM ctlm2000
WHERE user_id1 = '' )
OR '' = 'MANAGER'
)
ORDER BY saft04.cur_year ,
saft04.vdept_id ,
saft04.dept_id ,
saft04.fee_id ,
saft04.vitem_id ,
saft04.zone_id ,
saft04.corr_id ,
saft04.fc_app_no
-------------------------数据量统计----------------------------------
SELECT  COUNT(*)
FROM    saft04
WHERE   1 = 1
        AND saft04.com_id = 'LQPJ'
        AND saft04.cur_year = 2015
        AND saft04.dept_id LIKE '%2001%'
        AND ( saft04.dept_id IN ( SELECT    dept_id
                                  FROM      ctlm2000
                                  WHERE     user_id1 = '0100030' )
              OR '0100030' = 'MANAGER'
            )--904
SELECT COUNT(*) FROM  v_saft04_fexp  --1262584
SELECT COUNT(*) FROM  v_fadj_rd d --37077
SELECT COUNT(*) FROM  v_ctlm60 --431
SELECT COUNT(*) FROM  ctlm1000 --377

看了一下SQL,有可能出现问题的地方有2个地方,第一个是saft04 表的过滤条件“saft04.dept_id LIKE '%2001%'”使用了模糊查询,导致

走不了既定的索引。经和业务员确定,最开始只是想查询以“2001”开头的单位,因此,这个条件改成“saft04.dept_id LIKE '2001%'”即可。

第二个问题,是最要命的,标量部分“SELECT SUM(b.opr_amt) FROM v_saft04_fexp b WHERE b.fcapp_id = saft04.fc_app_no”走

的执行计划是嵌套循环,因而要改成左联接。

改写后的SQL如下,只执行了23S就全部出结果了。

WITH    x0
AS ( SELECT b.fcapp_id ,
SUM(b.opr_amt) opr_amt
FROM v_saft04_fexp b
GROUP BY b.fcapp_id
)
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_amt ,
ISNULL(saft04.fee_qty, 0) AS saft04_fee_qty ,
ISNULL(saft04.fee_amt_flex, 0) AS saft04_fee_amt_flex ,
ISNULL(saft04.adj_amt, 0) AS saft04_adj_amt ,
ISNULL(saft04.init_amt, 0) AS saft04_init_amt ,
ISNULL(saft04.flex_amt, 0) AS saft04_flex_amt ,
ISNULL(saft04.conf_fee_amt, 0) AS saft04_conf_fee_amt ,
saft04.fc_app_no ,
saft04.zone_id ,
saft04.corr_id ,
CASE WHEN saft04.fc_app_no < ''
THEN ( CASE WHEN saft04.flexfapp_flag = 'Y'
THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
- ISNULL(conf_fee_amt, 0)
ELSE ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
+ ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt,
0)
END )
ELSE CASE WHEN b.fee_type2 = ''
OR b.fee_type2 = ''
THEN ISNULL(fee_amt, 0) + ISNULL(adj_amt, 0)
- ISNULL(conf_fee_amt, 0)
WHEN b.fee_type2 = ''
THEN ISNULL(init_amt, 0) + ISNULL(flex_amt, 0)
+ ISNULL(adj_amt, 0) - ISNULL(conf_fee_amt, 0)
END
END bal_amt ,
ISNULL(( x0.opr_amt ), 0) AS qty1 ,
CASE WHEN b.fee_type2 = ''
OR b.fee_type2 = ''
THEN ISNULL(saft04.conf_fee_amt, 0) - ( ISNULL(( x0.opr_amt ),
0) )
WHEN b.fee_type2 = ''
THEN ISNULL(saft04.init_amt, 0) + ISNULL(saft04.flex_amt, 0)
- ISNULL(( x0.opr_amt ), 0)
+ ISNULL(( SELECT SUM(d.opr_amt)
FROM v_fadj_rd d
WHERE d.fcapp_id = saft04.fc_app_no
), 0)
END qty2 ,
c.base_data2
FROM saft04
LEFT JOIN v_ctlm60 b ON b.fee_id = saft04.fee_id
LEFT JOIN ctlm1000 c ON c.d_type = 'fee_type2'
AND b.fee_type2 = c.base_data1
LEFT JOIN x0 ON x0.fcapp_id = saft04.fc_app_no
WHERE 1 = 1
AND saft04.com_id = 'LQPJ'
AND saft04.cur_year = 2015
AND saft04.dept_id LIKE '2001%'
AND saft04.dept_id IN ( SELECT dept_id
FROM ctlm2000
WHERE user_id1 = '' )
ORDER BY saft04.cur_year ,
saft04.vdept_id ,
saft04.dept_id ,
saft04.fee_id ,
saft04.vitem_id ,
saft04.zone_id ,
saft04.corr_id ,
saft04.fc_app_no

改写后的SQL还有一个标量子查询没处理,改写的思路和上面一样,因执行时间已经缩短到23S,就不改了。

优化有标量子查询的SQL的更多相关文章

  1. 彻底搞懂oracle的标量子查询

    oracle标量子查询和自己定义函数有时用起来比較方便,并且开发者也常常使用.数据量小还无所谓.数据量大,往往存在性能问题. 下面測试帮助大家彻底搞懂标量子查询. SQL> create tab ...

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

    在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减 ...

  3. 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 a ...

  4. SQL优化-标量子查询(数据仓库设计的隐患-标量子查询)

    项目数据库集群出现了大规模节点宕机问题.经查询,问题在于几张表被锁.主要问题在于近期得几个项目在数据库SQL编写时大量使用了标量子查询. 为确定为题确实是由于数据表访问量超过单节点限制,做了一些测试. ...

  5. paip.sql索引优化----join 代替子查询法

    paip.sql索引优化----join 代替子查询法 作者Attilax ,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.n ...

  6. 标量子查询SQL改写

    一网友说下面sql跑的好慢,让我看看 sql代码: select er, cid, pid, tbl, zs, sy, (select count(sr.mobile_tele_no) from tb ...

  7. 标量子查询调优SQL

    fxnjbmhkk4pp4 select /*+ leading (wb,sb,qw) */ 'blocker('||wb.holding_session||':'||sb.username||')- ...

  8. [20180626]函数与标量子查询14.txt

    [20180626]函数与标量子查询14.txt --//前面看http://www.cnblogs.com/kerrycode/p/9099507.html链接,里面提到: 通俗来将,当使用标量子查 ...

  9. SELECT列表中的标量子查询

    发现了一种表连接新的写法,以前还没有这样写过或者见别人写过.跟同学聊天他们公司却很多人这样写,看来真的要学学sql了 表 CREATE TABLE `t_book` ( `FId` ) NOT NUL ...

随机推荐

  1. SQL Server数据库存在判断语句及系统表简介 转

    Transact-SQL Exists Sentences--判断数据库是否存在IF EXISTS(SELECT * FROM master.sysdatabases WHERE name=N'库名' ...

  2. AppScan修复漏洞:启用不安全的HTTP方法

    最近对于系统使用Appscan扫描出中危漏洞“启用不安全的HTTP方法,找了很多修复方法都不能达到效果. 漏洞截图: 漏洞描述: 危险级别   中危险 影响页面   整个WEB页面. 简短描述   管 ...

  3. Web---文件上传-用apache的工具处理、打散目录、简单文件上传进度

    我们需要先准备好2个apache的类: 上一个博客文章只讲了最简单的入门,现在来开始慢慢加深. 先过渡一下:只上传一个file项 index.jsp: <h2>用apache的工具处理文件 ...

  4. linux 命令拾遗

    man ascii 这个命令会打印出八进制.十六进制和十进制的ASCII码表. xxd xxd可以生成所给与文件的十六进制拷贝,也可以将编辑好的十六进制拷贝还原成二进制格式.它也可以将十六进制拷贝输出 ...

  5. JavaScript高级程序设计49.pdf

    HTML5事件 contextmenu事件 contextmenu事件是冒泡的,可以将事件处理程序指定到document,这个事件的目标是用户操作的元素,在兼容DOM的浏览器中使用event.prev ...

  6. linux内核中经常用到的设备初始化宏

    内核使用了大量不同的宏来标记具有不同作用的函数和数据结构.如宏__init.__devinit等.这些宏在include/linux/init.h头文件中定义.编译器通过这些宏可以把代码优化放到合适的 ...

  7. 一起来说 Vim 语

    作为一款古老而具有持久生命力的编辑器,vim 自有它的强大之处.很多人觉得 Vim 的学习曲线太陡峭了,为了能够把 Vim 用得风生水起,不得不记忆大量的命令.如果你是 Vim 新手,刚入门就开始面对 ...

  8. php 生成mysql数据字典代码

    由于项目开发用了比较多的表 ,为了快速获取数据字典,通过php代码的方式来获取表结构和表注释.代码如下: <?php /** * 生成mysql数据字典 */ header ( "Co ...

  9. VIM中的正则表达式及替换命令

    VIM中的正则表达式及替换命令 一.使用正则表达式的命令 使用正则表达式的命令最常见的就是 / (搜索)命令.其格式如下: /正则表达式 另一个很有用的命令就是 :s(替换)命令,将第一个//之间的正 ...

  10. Java 抽象类与接口总结

    一.为什么要使用抽象类?有什么好处? 抽象类是通用接口.不同的子类可以用不同的方法表示此接口.通用接口建立起一种基本形式,以此表示所有子类的共同部分. 必须覆写父类abstract抽象的方法  含有抽 ...