优化有标量子查询的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_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的更多相关文章
- 彻底搞懂oracle的标量子查询
oracle标量子查询和自己定义函数有时用起来比較方便,并且开发者也常常使用.数据量小还无所谓.数据量大,往往存在性能问题. 下面測试帮助大家彻底搞懂标量子查询. SQL> create tab ...
- SQL Server的优化器会缓存标量子查询结果集吗
在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减 ...
- 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 ...
- SQL优化-标量子查询(数据仓库设计的隐患-标量子查询)
项目数据库集群出现了大规模节点宕机问题.经查询,问题在于几张表被锁.主要问题在于近期得几个项目在数据库SQL编写时大量使用了标量子查询. 为确定为题确实是由于数据表访问量超过单节点限制,做了一些测试. ...
- paip.sql索引优化----join 代替子查询法
paip.sql索引优化----join 代替子查询法 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.n ...
- 标量子查询SQL改写
一网友说下面sql跑的好慢,让我看看 sql代码: select er, cid, pid, tbl, zs, sy, (select count(sr.mobile_tele_no) from tb ...
- 标量子查询调优SQL
fxnjbmhkk4pp4 select /*+ leading (wb,sb,qw) */ 'blocker('||wb.holding_session||':'||sb.username||')- ...
- [20180626]函数与标量子查询14.txt
[20180626]函数与标量子查询14.txt --//前面看http://www.cnblogs.com/kerrycode/p/9099507.html链接,里面提到: 通俗来将,当使用标量子查 ...
- SELECT列表中的标量子查询
发现了一种表连接新的写法,以前还没有这样写过或者见别人写过.跟同学聊天他们公司却很多人这样写,看来真的要学学sql了 表 CREATE TABLE `t_book` ( `FId` ) NOT NUL ...
随机推荐
- 【转】iOS开发者申请发布证书及真机调试图文详解
原文网址:http://www.tqcto.com/article/mobile/57822.html 打开iOS Dev Center,选择Sign in,登陆(至少99美元账号),登陆之后在网页右 ...
- 【转】Notepad++插件NppProject发布
原文网址:http://darkbull.net/article/NppProject/ 如果notepad++安装在 系统盘/program files/ 目录下,可能会提示错误.将npp移到其他目 ...
- HDOJ -- 4699
Editor Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Su ...
- WinDbg配置和使用基础
WinDbg配置和使用基础 WinDbg是微软发布的一款相当优秀的源码级(source-level)调试工具,可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件. 1. WinDbg介 ...
- NodeJS with Express 4.x
Express 4.x 静态资源目录设置: //静态文件目录 app.use('/public', express.static(__dirname+'/public')); app.use('/da ...
- GPU 的硬件基本概念,Cuda和Opencl名词关系对应
GPU 的硬件基本概念 Nvidia的版本: 实际上在 nVidia 的 GPU 里,最基本的处理单元是所谓的 SP(Streaming Processor),而一颗 nVidia 的 GPU 里,会 ...
- Arrays.sort源代码解析
Java Arrays.sort源代码解析 Java Arrays中提供了对所有类型的排序.其中主要分为Primitive(8种基本类型)和Object两大类. 基本类型:采用调优的快速排序: 对象类 ...
- 初级程序员应该了解的Linux命令
基于Linux的系统最美妙的一点,就是你可以在终端中使用命令行来管理整个系统.使用命令行的优势在于,你可以使用相同的知识和技能来管理随便哪个Linux发行版. 对于各个发行版以及桌面环境(DE)而言, ...
- 使用C++的开源序列化(Serialization)库cereal
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:使用C++的开源序列化(Serialization)库cereal.
- Creating custom datatypes using the umbraco usercontrol wrapper
本篇文章介绍的是基于UmbracoCMS技术搭建的网站所使用的相关技术. 1. 需求 Umbraco CMS的dataType中有richTexhEditor控件,但是它不是太完善,比如没有 ...