数据库环境: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. HDU-1701 Binary Tree Traversals

    http://acm.hdu.edu.cn/showproblem.php?pid=1710 已知先序和中序遍历,求后序遍历二叉树. 思路:先递归建树的过程,后后序遍历. Binary Tree Tr ...

  2. java 枚举(括号赋值)

    详解在这里 要注意的是: 1. 通过括号赋值,而且必须带有一个参构造器和一个属性跟方法,否则编译出错2. 赋值必须都赋值或都不赋值,不能一部分赋值一部分不赋值:如果不赋值则不能写构造器,赋值编译也出错 ...

  3. Javascript 查找字符串中出现最多的字符和出现的次数

    <script type="text/javascript"> //查找字符串中出现最多的字符和出现的次数 var str = 'Thatwheneying its o ...

  4. [SAM4N学习笔记]LED点灯程序

    一.准备工作:      将上一节搭建的工程模板复制一份,命名为"1.blink",这作为我们开发的第一个程序. 二.程序编写:      板子上只有一个可控制的LED,就是LED ...

  5. (DT系列一)DTS结构及其编译方法

    DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...

  6. Ubuntu 如何使用apt命令安装、升级、卸载软件

    apt-get是一条linux命令,适用于deb包管理式的操作系统,主要用于自动从互联网的软件仓库中搜索.安装.升级.卸载软件或操作系统. apt-get命令一般需要root权限执行,所以一般跟着su ...

  7. PL/SQL练习

    简单结构 set serveroutput on; DECLARE v_name ); BEGIN v_name := 'hello'; dbms_output.put_line(v_name); E ...

  8. oracle 语句优化

    1. 选用适合的ORACLE优化器         ORACLE的优化器共有3种: a. RULE (基于规则)   b. COST (基于成本) c. CHOOSE (选择性) 设置缺省的优化器,可 ...

  9. SignalR及时通知功能

    功能需求,现时已经编写了一个hub能够,将后台的消息发送至前台中,并给出提示,但如后台已经发生了变化,由内部调用消息时,应该怎样处理? 1.编写Hub类 using System.Collection ...

  10. 5种Web常见编码、变换算法的自动识别

    #coding=utf-8 #识别字符序列变换算法,当前支持标准的MD5.SHA-1.Base64,及主流的URL编码.HTML编码 import re import sys #MD5判断函数 def ...