当前位置: 首页 > article >正文

SQL调优分析200倍性能提升

原始SQL:

select
   distinct cert.emp_id 
from
   cm_log cl 
inner join
   (
     select
     emp.id as emp_id,
     emp_cert.id as cert_id 
     from
     employee emp 
     left join
     emp_certificate emp_cert 
     on emp.id = emp_cert.emp_id 
     where
     emp.is_deleted=0
   ) cert 
      on (
        cl.ref_table='Employee' 
        and cl.ref_oid= cert.emp_id
      ) 
      or (
        cl.ref_table='EmpCertificate' 
        and cl.ref_oid= cert.cert_id
      ) 
where
   cl.last_upd_date >='2013-11-07 15:03:00' 
   and cl.last_upd_date<='2013-11-08 16:00:00'

运行一下,53条记录 1.87秒,又没有用聚合语句,比较慢。

执行计划内容:

执行计划分析:

首先mysql根据idx_last_upd_date索引扫描cm_log表获得379条记录;然后查表扫描了63727条记录,分为两部分,derived表示构造表,也就是不存在的表,可以简单理解成是一个语句形成的结果集,后面的数字表示语句的ID。

derived2表示的是ID = 2的查询构造了虚拟表,并且返回了63727条记录。我们再来看看ID = 2的语句究竟做了写什么返回了这么大量的数据,首先全表扫描employee表13317条记录,然后根据索引emp_certificate_empid关联emp_certificate表,rows = 1表示,每个关联都只锁定了一条记录,效率比较高。

获得后,再和cm_log的379条记录根据规则关联。从执行过程上可以看出返回了太多的数据,返回的数据绝大部分cm_log都用不到,因为cm_log只锁定了379条记录。

优化思路:

可以看到我们在运行完后还是要和cm_log做join,那么我们能不能之前和cm_log做join呢?

仔细分析语句不难发现,其基本思想是如果cm_log的ref_table是EmpCertificate就关联emp_certificate表。如果ref_table是Employee就关联employee表。

我们完全可以拆成两部分,并用union连接起来,注意这里用union,而不用union all是因为原语句有“distinct”来得到唯一的记录,而union恰好具备了这种功能。

如果原语句中没有distinct不需要去重,我们就可以直接使用union all了,因为使用union需要去重的动作,会影响SQL性能。

优化后SQL:

select
   emp.id 
from
   cm_log cl 
inner join
   employee emp 
      on cl.ref_table = 'Employee' 
      and cl.ref_oid = emp.id  
where
   cl.last_upd_date >='2013-11-07 15:03:00' 
   and cl.last_upd_date<='2013-11-08 16:00:00' 
   and emp.is_deleted = 0  

union

select
   emp.id 
from
   cm_log cl 
inner join
   emp_certificate ec 
      on cl.ref_table = 'EmpCertificate' 
      and cl.ref_oid = ec.id  
inner join
   employee emp 
      on emp.id = ec.emp_id  
where
   cl.last_upd_date >='2013-11-07 15:03:00' 
   and cl.last_upd_date<='2013-11-08 16:00:00' 
   and emp.is_deleted = 0

运行一下,53条记录 0.01秒,速度提升187倍。

不需要了解业务场景,只需要改造的语句和改造之前的语句保持结果一致,现有索引可以满足,不需要建索引,用改造后的语句实验一下,只需要10ms 降低了近200倍!

执行计划内容:


http://www.kler.cn/a/418262.html

相关文章:

  • 【YOLO系列复现】二、基于YOLOv6的目标检测:YOLOv6训练自己的数据集(史诗级详细教程)
  • linux常用指令都是工作中遇到的
  • 【Android】EventBus的使用及源码分析
  • Java抛出自定义运行运行
  • Cisco FMC通过命令行导入配置
  • CSDN设置成黑色背景(谷歌 Edge)
  • Vue3+Echarts+echarts-wordcloud插件创建词云图
  • Docker命令总结
  • sys.stdout和sys.stdout.buffer
  • pnpm安装electron出现postinstall$ node install.js报错
  • 【中间件】Redis
  • 大模型开发和微调工具Llama-Factory-->量化1(GPTQ 和 AWQ)
  • Java并发07之ThreadLocal
  • fatal error:boostdesc_bgm.i:no such file or directory
  • 【学习笔记】基于RTOS的设计中的堆栈溢出(Stack Overflow)-第1部分
  • 前端项目中,通过命令行传入自定义参数
  • 排序-多语言
  • MySQL 利用JSON特性完成复杂数据存储和查询
  • 详解高斯消元
  • Axure PR 9 随机函数 设计交互
  • 每天五分钟机器学习:平行和重合
  • MySQL Workbench 数据库建模详解:从设计到实践
  • <三>51单片机PWM开发SG90和超声测距
  • C++中 测算 不定长数据 的 长度 的方法
  • 追寻红色足迹,领略西湖古韵今风|中共杭州美创科技有限公司支部党建活动纪实
  • ESP32-S3模组上跑通ES8388(9)