sql逻辑需求:需要定期统计表单数据,然后把汇总的结果展示在前端界面

根据业务逻辑实现了sql编写,产生了慢SQL
SELECT DISTINCT DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') as signDate,
                count(sr.PRODUCT_NO) as totalSign,
                (SELECT count(1)
                   FROM t_red_data t1
                  WHERE DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') =
                        DATE_FORMAT(t1.SIGN_DATE, '%Y-%m-%d')
                    AND t1.SIGN_TYPE = '1') AS sign,
                (SELECT count(1)
                   FROM t_red_data t2
                  WHERE DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') =
                        DATE_FORMAT(t2.SIGN_DATE, '%Y-%m-%d')
                    AND t2.SIGN_TYPE = '2') AS supplySign
  FROM t_red_data sr 
 WHERE sr.SIGN_DATE BETWEEN '2020-12-20 00:00:00' AND '2021-01-06 23:59:59'
 GROUP BY DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') LIMIT 0, 10;
 --耗费时间
 10 rows in set (15.32 sec)
上面这条sql 的执行时间用了15.32秒,下面来看看慢在哪儿?

执行计划:


这sql执行计划挺差的,虽然where条件列上有索引IDX_SIGN_DATE,但数据库CBO并没有选择,走了全表扫描,因为时间范围选的太大,CBO估算后发现走完索引再回表查数据,代价太高。

下面让该sql强制走索引IDX_SIGN_DATE 看看效果:

SELECT DISTINCT DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') as signDate,
                count(sr.PRODUCT_NO) as totalSign,
                (SELECT count(1)
                   FROM t_red_data t1
                  WHERE DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') =
                        DATE_FORMAT(t1.SIGN_DATE, '%Y-%m-%d')
                    AND t1.SIGN_TYPE = '1') AS sign,
                (SELECT count(1)
                   FROM t_red_data t2
                  WHERE DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') =
                        DATE_FORMAT(t2.SIGN_DATE, '%Y-%m-%d')
                    AND t2.SIGN_TYPE = '2') AS supplySign
  FROM t_red_data sr force index (IDX_SIGN_DATE)
 WHERE sr.SIGN_DATE BETWEEN '2020-12-20 00:00:00' AND '2021-01-06 23:59:59'
 GROUP BY DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') LIMIT 0, 10;
 --耗时时间更长了
 10 rows in set (15.94 sec)
强制索引后执行计划:


执行慢的原因总结:CBO选择的执行计划是对的,因为走索引后代价更高,sql更慢。耗时主要是出现在DEPENDENT SUBQUERY上,根据where条件相当于把该表执行了三遍。主要解决子查询的问题。

通过表自关联消除列上子查询
SELECT signDate, totalSign, sign, totalSign - sign AS supplySign
  FROM (SELECT DISTINCT DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') AS signDate,
                        count(sr.PRODUCT_NO) AS totalSign,
                        count(t1.ID) AS sign
          FROM t_red_data sr
          LEFT JOIN t_red_data t1
            ON sr.id = t1.id
           AND t1.SIGN_TYPE = '1'
         WHERE sr.SIGN_DATE BETWEEN '2020-12-20 00:00:00' AND
               '2021-01-06 23:59:59'
         GROUP BY DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') LIMIT 0, 10) t;
     
 --耗时时间
 10 rows in set (1.75 sec)
改为自关联查询后就快了很多,接下来看下执行计划:


从执行计划可以看出,sr表作为驱动表,根据where条件筛选数据后拿到id再去驱动t1表,按条件匹配到10条数据后就结束,效率看起来不错...

但是还没结束,仅仅是统计下不同条件上的数据量,真的有必要自关联查询么?

自关联改写为case when

SELECT DISTINCT DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') as signDate,
                count(sr.PRODUCT_NO) as totalSign,
                count(case when sr.SIGN_TYPE = '1' then '1' else null end ) AS sign,
                count(case when sr.SIGN_TYPE = '2' then '2' else null end ) AS supplySign
  FROM t_red_data sr
 WHERE sr.SIGN_DATE BETWEEN '2020-12-20 00:00:00' AND '2021-01-06 23:59:59'
 GROUP BY DATE_FORMAT(sr.SIGN_DATE, '%Y-%m-%d') LIMIT 0, 10;
 
 --执行耗时
 10 rows in set (0.75 sec)
执行效率又进一步提升了,再次开口执行计划发生了啥改变:


该sql也变得更简单了,做了按where条件过滤数据后再把group by的排序下,相对之前的sql少做了不少事情,效率自然就高。另外,已经有了group by字句,本身已经消除了重复数据,所以前面的distinct关键词可以去掉了。

使用redis缓存查询结果
上面的sql 执行时间0.75秒还是不满足。 和业务沟通确认,这张表上1天前的数据不会改动,也就是根据时间条件多次执行这条sql结果不会发生变化。

把当天第一次查询出来的结果集缓存到redis,当sql查询日期条件改变时把缓存失效掉。这样就可以查询一次多次使用,访问redis效率更高,毫秒级返回。

Mysql改写子查询SQL优化案例相关推荐

  1. 性能为王:SQL标量子查询的优化案例分析

    本篇整理内容是黄廷忠在"云和恩墨大讲堂"微信分享中的讲解案例,SQL优化及SQL审核,是从源头解决性能问题的根本手段,无论是开发人员还是DBA,都应当持续深入的学习SQL开发技能, ...

  2. mysql多表查询sql优化_SQL多表查询优化

    SQL优化 1.执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只要0.02秒,但是2张表联合统计就 ...

  3. 浅谈 MySQL 子查询及其优化

    2019独角兽企业重金招聘Python工程师标准>>> 使用过oracle或者其他关系数据库的DBA或者开发人员都有这样的经验,在子查询上都认为数据库已经做过优化,能够很好的选择驱动 ...

  4. mysql in 子查询优化_mysql in 子查询 容易优化

    mysql in 子查询 简单优化 大数量下,不要使用 in 嵌套子查询,性能很差,很容易卡死. ? 简单调整方式如下: select uid,nick_name from uc_users wher ...

  5. 浅谈mysql的子查询

    2019独角兽企业重金招聘Python工程师标准>>> mysql的子查询的优化一直不是很友好,一直有受业界批评比较多,也是我在sql优化中遇到过最多的问题之一,mysql在处理子查 ...

  6. MySQL子查询的优缺点_浅谈mysql的子查询

    浅谈mysql的子查询 mysql的子查询的优化一直不是很友好,一直有受业界批评比较多,也是我在sql优化中遇到过最多的问题之一,你可以点击这里 ,这里来获得一些信息,mysql在处理子查询的时候,会 ...

  7. 数据库周刊54丨2020 年度报告:PingCAP、腾讯云数据库、人大金仓、GoldenDB ;CPU 100% SQL优化案例;Mysql内存溢出处理;避免删库跑路黑天鹅……

    热门资讯 [1.PingCAP 2020 年度报告|相信开放的力量 [摘要]本文为PingCAP 2020年度报告.盘点了PingCAP里程碑大事件:完成D轮2.7亿美元融资,创造全球数据库历史新的里 ...

  8. 19_clickhouse,数据查询与写入优化,分布式子查询优化,外部聚合/排序优化,基于JOIN引擎的优化,SQL优化案例,物化视图提速,查询优化常用经验法则,选择和主键不一样的排序键,数据入库优化

    25.数据查询与写入优化 25.1.分布式子查询优化 25.1.1.分布式表的IN查询示例1(普通IN子查询.IN子查询为本地表) 25.1.2.分布式表的IN查询示例2(普通IN子查询.IN子查询为 ...

  9. mysql数据库子查询的使用_MySQL数据库使用子查询方式更新数据优化及思考

    [环境介绍] 云数据库MySQL 5.7 [背景描述] 业务需要:需要对16370077的表数据进行更新部分数据操作 UPDATE P_MOXXXX_REXXXX SET FISAVAILABLE = ...

最新文章

  1. Spark Streaming 编程新手入门指南
  2. smarty模板引擎_7-自定义函数
  3. 【Linux系统编程】可重入和不可重入函数
  4. 行为设计模式:中介者
  5. Android: 解决动画完成后位置恢复到初始位置的问题
  6. 【贪心】【高精度】zoj3987 Numbers
  7. Python学习之快速入门
  8. IDEA项目搭建六——使用Eureka和Ribbon进行项目服务化
  9. cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded 解决方法
  10. Java CSV操作(导出和导入)
  11. ping 查看IP——MAC——计算机名
  12. 空域、频域、时域的解释
  13. freeswitch借助fail2ban屏蔽骚扰注册
  14. 关于springboot的配置注册循序问题
  15. 19、论文解读:Intensity Scan Context: Coding Intensity and Geometry Relations for Loop Closure Detection
  16. TDM阅读笔记,在推荐系统的应用
  17. shiro权限鉴定框架
  18. Java自幂数计算及其算法改进
  19. 论文解析[10] Contextual Transformer Networks for Visual Recognition
  20. 什么是护网(HVV)?需要什么技能?

热门文章

  1. 【报告分享】2021企业营销数字化转型研究报告.pdf(附下载链接)
  2. Python实战从入门到精通第十三讲——返回多个值的函数
  3. 【论文】Awesome Relation Extraction Paper(关系抽取)(PART V)
  4. 电商独立站-谷歌SEO指标
  5. perl模块net mysql_Perl模块实例化DBI Forks“Mysql服务器已经消失”
  6. 2019年的流水账和总结
  7. IntelliJ IDEA 创建Java Web项目
  8. 不得不会的10点Java基础知识
  9. python没有return语句的函数将返回_为什么Python没有return返回值
  10. mysql数据索引失效_MySQL索引失效的几种情况