美文网首页MySQL优化及排查数据库
SQL优化:用case...when优化统计查询

SQL优化:用case...when优化统计查询

作者: 赵客缦胡缨v吴钩霜雪明 | 来源:发表于2019-06-25 17:33 被阅读248次

最近在做的项目,有很多统计数据的地方,由于数据量相对较多,之前写的查询语句查询五十万条数据大概需要十秒左右的样子,严重影响了效率。后来在网上寻找解决方案,利用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简单查询,所以执行效率自然就高了:

针对这个问题,如果大家有更好的方案或思路,欢迎留言。

相关文章

  • SQL优化:用case...when优化统计查询

    最近在做的项目,有很多统计数据的地方,由于数据量相对较多,之前写的查询语句查询五十万条数据大概需要十秒左右的样子,...

  • 11-mysqlSQL分析

    六星教育 - java-mysql优化1909 SQL优化 所谓SQL优化:基于MySQL的优化器查询规则来优化S...

  • Java面试题:数据库优化策略有哪些?

    1、Sql优化主要优化的还是查询, 优化查询的话, 索引优化是最有效的方案。 首先要根据需求写出结构良好的SQL,...

  • SQL Server 统计信息

    统计信息是如何提高SQL Server查询性能的?统计直方图用作在查询执行计划中查询优化器的选择依据。如果一个查询...

  • Presto统计信息

    表统计 Presto支持基于统计的查询优化。为了使查询能够利用这些优化,Presto必须具有该查询中表的统计信息。...

  • MySQL | 使用 limit 优化查询和防止SQL被优化

    使用 limit 优化查询和防止SQL被优化 Table of Contents 查询优化 1.1 最大值和最小值...

  • SQL优化

    SQL优化 在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有...

  • 17.MySQL优化

    《高性能MySQL》——这本书都有的 “字段”优化总结 “索引”优化总结 索引的优化 “查询SQL”优化总结 “引...

  • MySQL实战14 慢查询优化join、order by、gro

    1.慢查询的优化思路 1.1优化更需要优化的SQL 优化SQL是有成本的高并发低消耗的比低并发高消耗影响更大 优化...

  • 不可置信!SQL 优化终于干掉了“distinct”

    sql 优化之多表联合查询干掉 “distinct” 去重关键字 所以需要把多表的子查询的 sql 结构进行优化。...

网友评论

    本文标题:SQL优化:用case...when优化统计查询

    本文链接:https://www.haomeiwen.com/subject/bbsxcctx.html