标量子查询SQL改写
一网友说下面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改写的更多相关文章
- 标量子查询调优SQL
fxnjbmhkk4pp4 select /*+ leading (wb,sb,qw) */ 'blocker('||wb.holding_session||':'||sb.username||')- ...
- 优化有标量子查询的SQL
数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...
- 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 Server的优化器会缓存标量子查询结果集吗
在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减 ...
- SQL优化-标量子查询(数据仓库设计的隐患-标量子查询)
项目数据库集群出现了大规模节点宕机问题.经查询,问题在于几张表被锁.主要问题在于近期得几个项目在数据库SQL编写时大量使用了标量子查询. 为确定为题确实是由于数据表访问量超过单节点限制,做了一些测试. ...
- [20180626]函数与标量子查询14.txt
[20180626]函数与标量子查询14.txt --//前面看http://www.cnblogs.com/kerrycode/p/9099507.html链接,里面提到: 通俗来将,当使用标量子查 ...
- SELECT列表中的标量子查询
发现了一种表连接新的写法,以前还没有这样写过或者见别人写过.跟同学聊天他们公司却很多人这样写,看来真的要学学sql了 表 CREATE TABLE `t_book` ( `FId` ) NOT NUL ...
- WHERE 子句中的标量子查询
标量子查询不仅可以用在SELECT 语句的列表中,它还可以用在WHERE 子句中,而且实际应用中子查询很多的时候都是用在WHERE子句中的. 先来看一个简单的例子,我们要检索喜欢“Story”的读者主 ...
- 在MySQL中使用子查询和标量子查询的基本用法
一.MySQL 子查询 子查询是将一个 SELECT 语句的查询结果作为中间结果,供另一个 SQL 语句调用.MySQL 支持 SQL 标准要求的所有子查询格式和操作,也扩展了特有的几种特性.子查询没 ...
随机推荐
- [官方教程] Unity 5 BLACKSMITH深度分享 - 汇总帖
BLACKSMITH深度分享系列 相信此大片在Unite上的惊艳亮相,让许多人至今无法忘却它所带来的震撼,Unity的大师们为了让更多Unity开发者了解此大片是如何用Unity5诞生的,深度分享了多 ...
- bzoj 3796: Mushroom追妹纸【二分+后缀数组+st表】
把三个串加上ASCII大于z的分隔符连起来,然后求SA 显然每个相同子串都是一个后缀的前缀,所以枚举s1的每个后缀的最长和s2相同的前缀串(直接在排序后的数组里挨个找,最近的两个分别属于s1和s2的后 ...
- hdu 1171 Big Event in HDU【生成函数】
按套路列生成函数式子然后暴力乘,这样复杂度看起来非常大,但是可以动态维护最大值,这样就是O(能过)的了 仔细想想这个多项式暴力乘理解成背包dp也行? #include<iostream> ...
- Comet OJ - Contest #4--前缀和
原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...
- S.O.L.I.D: PHP 面向对象设计的五个基准原则
S.O.L.I.D 是首个 5 个面向对象设计 (OOD) 准则的首字母缩写,这些准则是由 Robert C. Martin 提出的,他更为人所熟知的名字是 Uncle Bob. 这些准则使得开发出易 ...
- 3分钟入门微信小程序直播
效果预览 开发环境搭建 安装微信开发者工具 相对于以前微信以前的产品来说.小程序在发布之初就面向开发者开放微信开发者工具.使开发者更加方便的开发和调试小程序.我们从官网下载安装.官网下载地址.现在 ...
- C++ 的输出格式
0 在C语言中很简单对输出的要求,然而在C++中有一丝的麻烦. 在下面的代码中所需要的是 #include<iostream> 基本输入/输出库 #include<iomanip&g ...
- div 四周都有阴影的写法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- AtCoder Grand Contest 015 E - Mr.Aoki Incubator
题目传送门:https://agc015.contest.atcoder.jp/tasks/agc015_e 题目大意: 数轴上有\(N\)个点,每个点初始时在位置\(X_i\),以\(V_i\)的速 ...
- 为页面添加favicon
<link rel="shortcut icon" href="favicon.ico" /> 还有另一种写法,但是IE对它的支持不够好: < ...