一次SQL优化的体验

点击上方 "程序员小乐"关注, 星标或置顶一起成长

每天凌晨00点00分, 第一时间与你相约

每日英文

If you’re brave to say “good bye”, life will reward you with a new “hello”. -- Paulo Coelho 

如果你勇于对过去说“拜拜”,生活就会回赠给你一个新的“哈喽”。

每日掏心

人的一生,没有谁是事事都是得意,真正的幸福那也是是脱离物质追求的一种心灵感受,幸福不受地位、权势、财富的约束,那就是人生路上坚强的表现。

来自:AmosZhu | 责编:乐乐

链接:jianshu.com/p/6dfc1d6ffcef

程序员小乐(ID:study_tech)第 737 次推文   图片来自 Pexels

往日回顾:2019年支付宝新增了4亿行代码堪比80个《魔兽世界》

   正文   

今天遇到一个SQL优化的问题,记录下来

测试部门反映,有个功能的查询很缓慢,需要支持排查下

首先描述下具体的问题

数据库中一张表的大概有700多条记录,业务需要模拟一个类似属性树形的数据结构,需要查询所有父类的列表数据,查询出来符合记录的大概有400多条,目前测试点击查询,所需要的时间大概在4s多,这个效率实在太慢了;

下面是SQL的内容

SELECT
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_interflow = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS url,
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_audit = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS source_url,
      id
    FROM
      unicom_send_recv_order t
    WHERE is_deleted = 0
      AND t.id IN
      (SELECT
        (SELECT
          b.id
        FROM
          unicom_send_recv_order b
        WHERE b.is_deleted = 0
          AND b.unicom_first_id = a.unicom_first_id
          AND (
            b.data_direction = 0
            OR (
              b.data_direction = 1
              AND (
                b.order_status = '1001516'
                OR b.order_status = '1001515'
              )
            )
            OR b.is_start_line = 1
          )
        ORDER BY b.send_recv_count DESC
        LIMIT 1)
      FROM
        unicom_send_recv_order a
      WHERE a.is_deleted = 0
      GROUP BY a.unicom_first_id)
    ORDER BY t.created_time DESC

这个sql的逻辑,在满足一定的条件下,选择send_recv_count最大的那条记录的id来展示。


添加索引

在不影响业务的条件下,我们通过添加索引来试试,查看表中的关联字段,我们需要对如下的字段添加索引

      ALTER TABLE `sceo`.`unicom_send_recv_order`   
      ADD  INDEX `index_unicom_first_id` (`unicom_first_id`),
      ADD  INDEX `index_from_oddf_class_no` (`from_oddf_class_no`),
      ADD  INDEX `index_send_recv_count` (`send_recv_count`);
      ALTER TABLE `sceo`.`order_def_form_relation`   
      ADD  INDEX `index_pid` (`pid`),
      ADD  INDEX `index_form_id` (`form_id`);

再次执行该上面的sql语句,发现查询的效率变快了了,耗时2700+ms数,这个时间还是满足不了业务的需要


重构SQL

分析上述的sql,发现在子查询中通过排序来获取send_recv_count最大的记录,然后再分组查询,这个是主要导致查询效率缓慢的原因,我们可以改写sql语句来减少分组和排序

我们利用变量来为排序标记,然后获取变量为1的记录,利用这种方式来避免排序分组, 重构的sql如下:

SELECT
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_interflow = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS url,
      (SELECT
        MAX(f.url)
      FROM
        order_definnition o
         JOIN order_def_form_relation d
          ON o.id = d.pid
          AND d.is_audit = 1
          AND o.is_deleted = 0
          AND d.is_deleted = 0
         JOIN form f
          ON f.id = d.form_id
          AND f.is_deleted = 0
      WHERE o.resource_code = t.from_oddf_class_no) AS source_url, id
    FROM
      unicom_send_recv_order t
    WHERE is_deleted = 0
       AND EXISTS
      (SELECT tt.id from (SELECT
        b.id,
        b.unicom_first_id,
        send_recv_count,
    IF (
        @pre_course_id = b.unicom_first_id,
        @cur_rank := @cur_rank + 1,
        @cur_rank := 1
    ) ranking,
     @pre_course_id := b.unicom_first_id
    FROM
        unicom_send_recv_order b,
        (SELECT
                @cur_rank := 0,
                @pre_course_id := NULL
        ) r
    where b.is_deleted = 0 
          AND (b.data_direction = 0
           OR (b.data_direction = 1
              AND (b.order_status = '1001516'
                OR b.order_status = '1001515'))
            OR b.is_start_line = 1)
    ORDER BY
        unicom_first_id,
        send_recv_count DESC) tt where tt.ranking = 1
        AND tt.id = t.id)
    ORDER BY t.created_time DESC

在重构后的sql中,可以看到我们排序之后的记录添加一个序列,然后获取序列的第一条来作为我们现实的记录,然后将in改为exists,这样优化后的查询就变得效率很高了,经过测试,耗时降到了200ms,这个速度暂时是可以接受的了

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。

欢迎各位读者加入程序员小乐技术群,在公众号后台回复“加群”或者“学习”即可。

猜你还想看

阿里、腾讯、百度、华为、京东最新面试题汇集

Redis Sentinel 架构原理详解

面试官问:平常你是怎么对Java服务进行调优的?

程序员喜欢的 5 款最佳最牛掰代码比较工具

关注「程序员小乐」,收看更多精彩内容

嘿,你在看吗

\

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值