数据库环境: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-2527 Safe Or Unsafe

    http://acm.hdu.edu.cn/showproblem.php?pid=2527 建哈夫曼树,哈夫曼编码,求wpl值. Safe Or Unsafe Time Limit: 2000/10 ...

  2. smarty模板中类似for的功能实现

    1. 功能说明,在页面使用smarty循环100次输出,类似for循环100次 {section name=total loop=100} {$smarty.section.total.index+1 ...

  3. 洛谷1440 求m区间内的最小值

    洛谷1440 求m区间内的最小值 本题地址:http://www.luogu.org/problem/show?pid=1440 题目描述 一个含有n项的数列(n<=2000000),求出每一项 ...

  4. Bzoj 2456: mode 数论,众数

    2456: mode Time Limit: 1 Sec  Memory Limit: 1 MBSubmit: 2843  Solved: 1202[Submit][Status][Discuss] ...

  5. 【基于spark IM 的二次开发笔记】第二天 树形结构

    MessageTreePlugin.java final MessageTreeTab messageTreeTab = new MessageTreeTab(); /** * Adds a tab  ...

  6. 采集爬虫中,解决网站限制IP的问题? - wendi_0506的专栏 - 博客频道 - CSDN.NET

    采集爬虫中,解决网站限制IP的问题? - wendi_0506的专栏 - 博客频道 - CSDN.NET undefined

  7. 【SQL】MySQL内置函数中的字符串函数和日期时间函数

    字符串函数 --拼接字符串组成新的字符串 Select concat(‘A’,’B’); --返回字符串长度 Select length(“CAT”) --返回子字符串在字符串中首次出现的位置,没有返 ...

  8. 【python自动化第二篇:python入门】

    内容概览 模块 python运行过程 基本数据类型(数字,字符串) 序列类型(列表,元组,字典) 模块使用 模块我们可以把它想象成导入到python以增强其功能的一种拓展.需要使用import来导入模 ...

  9. .NET中ToString()的用法

    一.数字转换到字符串 格式说明符     说明       示例                         输出 C                 货币      2.5.ToString(& ...

  10. 搭建PHP开发环境 apache+MySQL+PHP 安装phpMyAdmin模块

    该博文参考的资料来源于: http://wenku.baidu.com/view/0e4c569ddd3383c4bb4cd267.html http://www.cnblogs.com/pharen ...