问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

mysql 跨表sum优化

发布网友 发布时间:2022-04-10 09:18

我来回答

2个回答

懂视网 时间:2022-04-10 13:39

最近在公司做项目,涉及到开发统计报表相关的任务,由于数据量相对较多,之前写的查询语句查询五十万条数据大概需要十秒左右的样子,后来经过老大的指点利用sum,case...when...重写SQL性能一下子提高到一秒钟就解决了。这里为了简洁明了的阐述问题和解决的方法,我简化一下需求模型。

现在数据库有一张订单表(经过简化的中间表),表结构如下:

CREATE TABLE `statistic_order` (
 `oid` bigint(20) NOT NULL,
 `o_source` varchar(25) DEFAULT NULL COMMENT ‘来源编号‘,
 `o_actno` varchar(30) DEFAULT NULL COMMENT ‘活动编号‘,
 `o_actname` varchar(100) DEFAULT NULL COMMENT ‘参与活动名称‘,
 `o_n_channel` int(2) DEFAULT NULL COMMENT ‘商城平台‘,
 `o_clue` varchar(25) DEFAULT NULL COMMENT ‘线索分类‘,
 `o_star_level` varchar(25) DEFAULT NULL COMMENT ‘订单星级‘,
 `o_saledep` varchar(30) DEFAULT NULL COMMENT ‘营销部‘,
 `o_style` varchar(30) DEFAULT NULL COMMENT ‘车型‘,
 `o_status` int(2) DEFAULT NULL COMMENT ‘订单状态‘,
 `syctime_day` varchar(15) DEFAULT NULL COMMENT ‘按天格式化日期‘,
 PRIMARY KEY (`oid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

项目需求是这样的:

统计某段时间范围内每天的来源编号数量,其中来源编号对应数据表中的o_source字段,字段值可能为CDE,SDE,PDE,CSE,SSE。

 

  技术分享图片 来源分类随时间流动

一开始写了这样一段SQL:

select S.syctime_day,
 (select count(*) from statistic_order SS where SS.syctime_day = S.syctime_day and SS.o_source = ‘CDE‘) as ‘CDE‘,
 (select count(*) from statistic_order SS where SS.syctime_day = S.syctime_day and SS.o_source = ‘CDE‘) as ‘SDE‘,
 (select count(*) from statistic_order SS where SS.syctime_day = S.syctime_day and SS.o_source = ‘CDE‘) as ‘PDE‘,
 (select count(*) from statistic_order SS where SS.syctime_day = S.syctime_day and SS.o_source = ‘CDE‘) as ‘CSE‘,
 (select count(*) from statistic_order SS where SS.syctime_day = S.syctime_day and SS.o_source = ‘CDE‘) as ‘SSE‘
 from statistic_order S where S.syctime_day > ‘2016-05-01‘ and S.syctime_day < ‘2016-08-01‘ 
 GROUP BY S.syctime_day order by S.syctime_day asc;

这种写法采用了子查询的方式,在没有加索引的情况下,55万条数据执行这句SQL,在workbench下等待了将近十分钟,最后报了一个连接中断,通过explain解释器可以看到SQL的执行计划如下:

  技术分享图片  

每一个查询都进行了全表扫描,五个子查询DEPENDENT SUBQUERY说明依赖于外部查询,这种查询机制是先进行外部查询,查询出group by后的日期结果,然后子查询分别查询对应的日期中CDE,SDE等的数量,其效率可想而知。

在o_source和syctime_day上加上索引之后,效率提高了很多,大概五秒钟就查询出了结果:

  技术分享图片  


查看执行计划发现扫描的行数减少了很多,不再进行全表扫描了:

 

  技术分享图片  

这当然还不够快,如果当数据量达到百万级别的话,查询速度肯定是不能容忍的。一直在想有没有一种办法,能否直接遍历一次就查询出所有的结果,类似于遍历java中的list集合,遇到某个条件就计数一次,这样进行一次全表扫描就可以查询出结果集,结果索引,效率应该会很高。在老大的指引下,利用sum聚合函数,加上case...when...then...这种“陌生”的用法,有效的解决了这个问题。
具体SQL如下:

 select S.syctime_day,
 sum(case when S.o_source = ‘CDE‘ then 1 else 0 end) as ‘CDE‘,
 sum(case when S.o_source = ‘SDE‘ then 1 else 0 end) as ‘SDE‘,
 sum(case when S.o_source = ‘PDE‘ then 1 else 0 end) as ‘PDE‘,
 sum(case when S.o_source = ‘CSE‘ then 1 else 0 end) as ‘CSE‘,
 sum(case when S.o_source = ‘SSE‘ then 1 else 0 end) as ‘SSE‘
 from statistic_order S where S.syctime_day > ‘2015-05-01‘ and S.syctime_day < ‘2016-08-01‘ 
 GROUP BY S.syctime_day order by S.syctime_day asc;

关于MySQL中case...when...then的用法就不做过多的解释了,这条SQL很容易理解,先对一条一条记录进行遍历,group by对日期进行了分类,sum聚合函数对某个日期的值进行求和,重点就在于case...when...then对sum的求和巧妙的加入了条件,当o_source = ‘CDE‘的时候,计数为1,否则为0;当o_source=‘SDE‘的时候......
这条语句的执行只花了一秒多,对于五十多万的数据进行这样一个维度的统计还是比较理想的。

  技术分享图片  

 

通过执行计划发现,虽然扫描的行数变多了,但是只进行了一次全表扫描,而且是SIMPLE简单查询,所以执行效率自然就高了:

  技术分享图片  

 

MySQL巧用sum,case...when...优化统计查询

标签:过多   遍历   pos   plain   containe   workbench   外部   data   -o   

热心网友 时间:2022-04-10 10:47

本来你的语句很漂亮,用不着优化。如果你实在很关心性能,可以在WHERE部分*一下【净入库.`入库日期`】的时间范围在1~9月,避免全表浏览,如果该字段有索引,可以快一点点。


AND 净入库.`入库日期`  BETWEEN  '2016-01-01 00:00:00.0' AND '2016-09-30 00:00:00.0'


SELECT
zc.纳税人名称,
sum(CASE
WHEN  净入库.`征收项目` = '城镇土地使用税' THEN
净入库.实缴金额
ELSE
0
END) 土地使用税,
sum(CASE
WHEN  净入库.`征收项目` = '房产税' THEN
净入库.实缴金额
ELSE
0
END) 房产税
FROM
清册 zc,
净入库
WHERE
 zc.`登记序号` =净入库.登记序号
 AND 净入库.`入库日期`  BETWEEN  '2016-01-01 00:00:00.0' AND '2016-09-30 00:00:00.0'
group by  zc.`登记序号`

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
《像素大战》国内什么时候上映? 求像素大战桌面吐血整理资源嘛,高清免费谢谢!! 请问哪位大侠知道全国那个城市出版社最多?说的具体一点,谢谢!_百度知... 老公出轨外遇背叛老婆,老婆要求老公父母给老婆父母道歉怎么办? 绿化黄刺玫去哪里买? ...什么样的人比较需苗木?公司内负责苗木采购的是哪个部门,怎样和他 ... 建筑公司里负责绿化的是什么部门 tcp/ip协议每个层次的功能 oracle数据库启动关闭与数据备份 oracle数据库怎么备份啊 mysql数据库sum,case.when.使用有什么影响 农业银行360天的理财产品中低风险的,到期后是不是自动把钱打到卡里, 钉钉怎么检查假期手写作业? excel用left函数求学号 excel使用left函数截取年份的问题 在这道excel2010题目中,如何用if等函数计算表中每个同学的性别,使用left函数为年级列填 新款沃尔沃S90实拍,新增水晶档把,换全新混动系统 crystal在手表上是什末零件? 配置升级/换水晶档杆 全新沃尔沃S90/V90家族官图发布 水晶振动子它的工作原理是什么? 水晶(Rock Crystal) 搭载轻混系统!新款的沃尔沃S90正式上市! 佩带水晶后的反应 电子手表上有一个圆形的框框,上面是一闪一闪的,一秒一动,不知道是 7时15分又26秒电子表怎么表示 运动手表一闪一闪是干嘛的? 四川省三台水晶电子有限公司怎么样? 水晶和电子产品放一起会消磁吗? 浙江水晶电子集团股份有限公司怎么样? 各位大神,mysql 帮我优化下以下查询语句啊,给点意见也好,新手求助,多谢,多谢! 鬼吹灯与盗墓笔记,究竟有哪些联系? 鬼吹灯是什么类型的小说? 你喜欢鬼吹灯、盗墓笔记这类型的小说吗? 鬼吹灯与盗墓笔记,有什么样的联系? 鬼吹灯 是什么样的一部书? 鬼吹灯 是什么类的小说啊? 鬼吹灯是什么样的小说?作者是谁? 有几部? 盗墓笔记和鬼吹灯都是盗墓类型的小说,哪部小说更加的精彩? 鬼吹灯是什么性质的小说 开公司必须开公司账户吗 公司开独立账户有什么要求 投资者说人类在18世纪发现了儿童,19世纪发现了妇女,20世纪发现银发经济? MySql统计查询 使用纯select 实现 急,在线等 战亚楠和班梦阳是小说人物吗 是的话求小说名 班梦阳和战亚楠什么时候恋爱的? 班梦阳现和战亚楠分手之后在怎么样 班梦阳和战亚楠是同性恋吗 战亚楠和班梦阳是谁? 战亚楠班梦阳为什么分手 战亚楠和班梦阳为什么分手