一网友说下面sql跑的好慢,让我看看

sql代码:

select er,
cid,
pid,
tbl,
zs,
sy,
(select count(sr.mobile_tele_no)
from tbl_sp_sales_records sr
where sr.task_id = tid
and sr.channel_id = cid
and sr.is_conn = '1'
and sr.sales_time >='2017-10-01 00:00:00'
and sr.sales_time <='2017-10-27 00:00:00'
) hc1,
(select count(sr.mobile_tele_no)
from tbl_sp_sales_records sr
where sr.task_id = tid
and sr.channel_id = cid
and sr.is_conn = '0'
and sr.sales_time >='2017-10-01 00:00:00'
and sr.sales_time <='2017-10-27 00:00:00'
) hc2,
(select count(1)
from tbl_disturb_customer_records cr
where cr.target_name = tbl
and cr.disturb_type in ('98', '99')) gz,
(select count(1)
from tbl_disturb_customer_records cr
where cr.target_name = tbl
and cr.disturb_type not in ('98', '99')) mr
from (select c.creator er,
tt.target_data tbl,
t.channel_id cid,
c.create_time ctime,
t.task_id tid,
c.campaign_id pid,
count_table_num_by_channelid(tt.target_data, t.channel_id) zs,
count_table_num(tt.target_data) sy
from tbl_sp_campaign c,
tbl_sp_task t,
tbl_task_targetdata tt
where c.campaign_id = t.campaign_id
and t.task_id = tt.task_id
and c.creator in ('fuzhou',
'lingde',
'longyan',
'nanping',
'putian',
'quanzhou',
'sanming',
'xiamen',
'zhangzhou')
and c.create_time >= '2017-10-01 00:00:00'
and c.create_time <= '2017-10-27 00:00:00')

执行计划

PLAN_TABLE_OUTPUT
Plan hash value: 2087309529 --------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 670 | 14 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 74 | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | TBL_SP_SALES_RECORDS | 1 | 74 | 9 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IDX_SSR_STAREA | 7 | | 4 (0)| 00:00:01 |
| 4 | SORT AGGREGATE | | 1 | 74 | | |
|* 5 | TABLE ACCESS BY INDEX ROWID | TBL_SP_SALES_RECORDS | 1 | 74 | 9 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_SSR_STAREA | 7 | | 4 (0)| 00:00:01 |
| 7 | SORT AGGREGATE | | 1 | 26 | | |
|* 8 | TABLE ACCESS BY INDEX ROWID | TBL_DISTURB_CUSTOMER_RECORDS | 289 | 7514 | 82 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | IDX_TARGET_NAME | 2993 | | 20 (0)| 00:00:01 |
| 10 | SORT AGGREGATE | | 1 | 26 | | |
|* 11 | TABLE ACCESS BY INDEX ROWID | TBL_DISTURB_CUSTOMER_RECORDS | 4058 | 103K| 82 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IDX_TARGET_NAME | 2993 | | 20 (0)| 00:00:01 |
|* 13 | HASH JOIN | | 5 | 670 | 14 (8)| 00:00:01 |
|* 14 | HASH JOIN | | 5 | 450 | 11 (10)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID| TBL_SP_CAMPAIGN | 5 | 225 | 7 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_P_CREATE_TIME | 6 | | 2 (0)| 00:00:01 |
| 17 | TABLE ACCESS FULL | TBL_SP_TASK | 112 | 5040 | 3 (0)| 00:00:01 |
| 18 | TABLE ACCESS FULL | TBL_TASK_TARGETDATA | 112 | 4928 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("SR"."TASK_ID"=:B1 AND "SR"."CHANNEL_ID"=:B2 AND "SR"."IS_CONN"='1')
3 - access("SR"."SALES_TIME">='2017-10-01 00:00:00' AND "SR"."SALES_TIME"<='2017-10-27 00:00:00')
filter(SUBSTR("SALES_TIME",1,10)>='2017-10-01' AND SUBSTR("SALES_TIME",1,10)<='2017-10-27')
5 - filter("SR"."TASK_ID"=:B1 AND "SR"."CHANNEL_ID"=:B2 AND "SR"."IS_CONN"='0')
6 - access("SR"."SALES_TIME">='2017-10-01 00:00:00' AND "SR"."SALES_TIME"<='2017-10-27 00:00:00')
filter(SUBSTR("SALES_TIME",1,10)>='2017-10-01' AND SUBSTR("SALES_TIME",1,10)<='2017-10-27')
8 - filter("CR"."DISTURB_TYPE"='98' OR "CR"."DISTURB_TYPE"='99')
9 - access("CR"."TARGET_NAME"=:B1)
11 - filter("CR"."DISTURB_TYPE"<>'98' AND "CR"."DISTURB_TYPE"<>'99')
12 - access("CR"."TARGET_NAME"=:B1)
13 - access("T"."TASK_ID"="TT"."TASK_ID")
14 - access("C"."CAMPAIGN_ID"="T"."CAMPAIGN_ID")
15 - filter("C"."CREATOR"='fuzhou' OR "C"."CREATOR"='lingde' OR "C"."CREATOR"='longyan' OR
"C"."CREATOR"='nanping' OR "C"."CREATOR"='putian' OR "C"."CREATOR"='quanzhou' OR
"C"."CREATOR"='sanming' OR "C"."CREATOR"='xiamen' OR "C"."CREATOR"='zhangzhou')
16 - access("C"."CREATE_TIME">='2017-10-01 00:00:00' AND "C"."CREATE_TIME"<='2017-10-27 00:00:00')

分析

我跟网友说:让他去掉sql里的标量,运行一次,他说很快

性能瓶颈在于标量子查询上,大家都知道,标量子查询可以改写成left join

改写后代码

select er,
cid,
pid,
tbl,
zs,
sy,
p. hc1,
p. hc2,
p2.gz,
p2. mr
from (select c.creator er,
tt.target_data tbl,
t.channel_id cid,
c.create_time ctime,
t.task_id tid,
c.campaign_id pid,
count_table_num_by_channelid(tt.target_data, t.channel_id) zs,
count_table_num(tt.target_data) sy
from tbl_sp_campaign c, tbl_sp_task t, tbl_task_targetdata tt
where c.campaign_id = t.campaign_id
and t.task_id = tt.task_id
and c.creator in ('fuzhou',
'lingde',
'longyan',
'nanping',
'putian',
'quanzhou',
'sanming',
'xiamen',
'zhangzhou')
and c.create_time >= '2017-10-01 00:00:00'
and c.create_time <= '2017-10-27 00:00:00') c
left join (select
sr.task_id,
sr.channel_id,
count(decode(sr.is_conn,1,sr.mobile_tele_no)) hc1,
count(decode(sr.is_conn,0,sr.mobile_tele_no)) hc2,
from tbl_sp_sales_records sr
where sr.sales_time >='2017-10-01 00:00:00'
and sr.sales_time <='2017-10-27 00:00:00'
group by sr.task_id,sr.channel_id)p
on (p.task_id = c.tid and p.channel_id = c.cid)
left join (select
count(case when disturb_type in ('98', '99') then 1 end )gz,
count(case when disturb_type not in ('98', '99') then 1 end )mr,
target_name
from tbl_disturb_customer_records
group by target_name) p2
on (p2.target_name = c.tbl)

执行计划



PLAN_TABLE_OUTPUT
Plan hash value: 4214787203 -----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 1160 | 435 (1)| 00:00:06 |
| 1 | NESTED LOOPS OUTER | | 5 | 1160 | 435 (1)| 00:00:06 |
|* 2 | HASH JOIN | | 5 | 1020 | 25 (12)| 00:00:01 |
|* 3 | HASH JOIN OUTER | | 5 | 800 | 21 (10)| 00:00:01 |
|* 4 | HASH JOIN | | 5 | 450 | 11 (10)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID | TBL_SP_CAMPAIGN | 5 | 225 | 7 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IDX_P_CREATE_TIME | 6 | | 2 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL | TBL_SP_TASK | 112 | 5040 | 3 (0)| 00:00:01 |
| 8 | VIEW | | 7 | 490 | 10 (10)| 00:00:01 |
| 9 | HASH GROUP BY | | 7 | 518 | 10 (10)| 00:00:01 |
| 10 | TABLE ACCESS BY INDEX ROWID| TBL_SP_SALES_RECORDS | 7 | 518 | 9 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | IDX_SSR_STAREA | 7 | | 4 (0)| 00:00:01 |
| 12 | TABLE ACCESS FULL | TBL_TASK_TARGETDATA | 112 | 4928 | 3 (0)| 00:00:01 |
| 13 | VIEW PUSHED PREDICATE | | 1 | 28 | 82 (0)| 00:00:01 |
| 14 | SORT GROUP BY | | 1 | 26 | 82 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | TBL_DISTURB_CUSTOMER_RECORDS | 4342 | 110K| 82 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_TARGET_NAME | 2993 | | 20 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("T"."TASK_ID"="TT"."TASK_ID")
3 - access("P"."CHANNEL_ID"(+)="T"."CHANNEL_ID" AND "P"."TASK_ID"(+)="T"."TASK_ID")
4 - access("C"."CAMPAIGN_ID"="T"."CAMPAIGN_ID")
5 - filter("C"."CREATOR"='fuzhou' OR "C"."CREATOR"='lingde' OR "C"."CREATOR"='longyan' OR
"C"."CREATOR"='nanping' OR "C"."CREATOR"='putian' OR "C"."CREATOR"='quanzhou' OR "C"."CREATOR"='sanming'
OR "C"."CREATOR"='xiamen' OR "C"."CREATOR"='zhangzhou')
6 - access("C"."CREATE_TIME">='2017-10-01 00:00:00' AND "C"."CREATE_TIME"<='2017-10-27 00:00:00')
11 - access("SR"."SALES_TIME">='2017-10-01 00:00:00' AND "SR"."SALES_TIME"<='2017-10-27 00:00:00')
filter(SUBSTR("SALES_TIME",1,10)>='2017-10-01' AND SUBSTR("SALES_TIME",1,10)<='2017-10-27')
16 - access("TARGET_NAME"="TT"."TARGET_DATA")

如果大家有兴趣,可以拿着以下sql代码进行测试。

改写前的:

select d.department_id,
d.department_name,
d.location_id,
NVL((select SUM(e.salary)
from employees e
where e.department_id = d.department_id
and e.job_id = 'IT_PROG'),
0) IT_SAL,
NVL((select SUM(e.salary)
from employees e
where e.department_id = d.department_id
and e.job_id = 'AD_VP'),
0) VP_SAL,
NVL((select SUM(e.salary)
from employees e
where e.department_id = d.department_id
and e.job_id = 'FI_ACCOUNT'),
0) FI_SAL,
NVL((select SUM(e.salary)
from employees e
where e.department_id = d.department_id
and e.job_id = 'PU_CLERK'),
0) PU_SAL
from departments d

改写后的:

select d.department_id,
d.department_name,
d.location_id,
nvl(c.it_sal1,0) it_sal ,
nvl(c.vp_sal1,0) vp_sal ,
nvl(c.fi_sal1,0) fi_sal ,
nvl(c.pu_sal1,0) pu_sal
from departments d
left join (select sum(case when e.job_id='IT_PROG' then e.salary end) it_sal1 ,
sum(case when e.job_id='AD_VP' then e.salary end) vp_sal1 ,
sum(case when e.job_id='FI_ACCOUNT' then e.salary end) fi_sal1 ,
sum(case when e.job_id='PU_CLERK' then e.salary end) pu_sal1,
e.department_id
from employees e group by e.department_id) c
on d.department_id=c.department_id ;

标量子查询SQL改写的更多相关文章

  1. 标量子查询调优SQL

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

  2. 优化有标量子查询的SQL

    数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...

  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 Server的优化器会缓存标量子查询结果集吗

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

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

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

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

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

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

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

  8. WHERE 子句中的标量子查询

    标量子查询不仅可以用在SELECT 语句的列表中,它还可以用在WHERE 子句中,而且实际应用中子查询很多的时候都是用在WHERE子句中的. 先来看一个简单的例子,我们要检索喜欢“Story”的读者主 ...

  9. 在MySQL中使用子查询和标量子查询的基本用法

    一.MySQL 子查询 子查询是将一个 SELECT 语句的查询结果作为中间结果,供另一个 SQL 语句调用.MySQL 支持 SQL 标准要求的所有子查询格式和操作,也扩展了特有的几种特性.子查询没 ...

随机推荐

  1. POJ1236【图的前连通(缩点)】

    题意: 1.初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件. 2.至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件. ...

  2. template code 引用的一些问题

    1.问题: 引用同一个norlib.tt 下面的tt  . 一个KSTrade 正确. 一个 NDAP就报错. 报错说源文件某个函数有错误 helper.Common.tt 错误 2.结果: NDAP ...

  3. 鸟哥私房菜基础篇:认识与学习BASH习题

    猫宁!!! 参考链接:http://linux.vbird.org/linux_basic/0320bash.php 鸟哥是为中国信息技术发展做出巨大贡献的人. 1-在 Linux 上可以找到哪些 s ...

  4. PJzhang:左耳朵耗子-陈皓

    猫宁!!! 参考链接:https://coolshell.cn/haoel 左耳朵耗子原名陈皓,那个是他的网络ID,在我眼中是个值得尊敬的程序员,虽然我对他真人没什么了解. 这是他博客的自我介绍: 2 ...

  5. C#递归拷贝文件夹下文件以及文件夹

    public bool CopyOldLabFilesToNewLab(string sourcePath, string savePath) { if (!Directory.Exists(save ...

  6. Hexo瞎折腾系列(7) - Coding Pages申请SSL/TLS证书错误

    问题 今天我的个人站点SSL/TLS证书到期,我的证书是由Coding Pages提供的,每次申请成功后有效期是三个月,证书到期后可以继续免费申请.但是当我登陆进入Coding Pages服务的后台并 ...

  7. JSP | 基础 | 新建Hello world 的三种方式

    第一种: 直接写一个 test.jsp 文件到ROOT文件目录下,内容如下,访问 “http://localhost:8080/test.jsp” <%-- Licensed to the Ap ...

  8. 模板——扩展欧几里得算法(求ax+by=gcd的解)

    Bryce1010模板 /**** *扩展欧几里得算法 *返回d=gcd(a,b),和对应等式ax+by=d中的x,y */ long long extend_gcd(long long a,long ...

  9. The 17th Zhejiang University Programming Contest Sponsored by TuSimple J

    Knuth-Morris-Pratt Algorithm Time Limit: 1 Second      Memory Limit: 65536 KB In computer science, t ...

  10. 双端队列 HDOJ 3530 Subsequence

    题目传送门 题意:问最长子序列,满足区间最大值 - 最小值在[m, k]之间 分析:用双端队列维护最大值和最小值,保存的是位置.当满足条件时,更新最大值. /********************* ...