当前位置:首页 > 文章列表 > 数据库 > MySQL > 通过一次慢SQL优化来看EXPLAIN

通过一次慢SQL优化来看EXPLAIN

来源:SegmentFault 2023-01-13 16:27:54 0浏览 收藏

数据库小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《通过一次慢SQL优化来看EXPLAIN》带大家来了解一下通过一次慢SQL优化来看EXPLAIN,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力实战开发!

实操

这条慢SQL主要涉及了两个表。

API_RESULT —— 用于统计api调用结果(数据量为6000W+)

1,MySQL是选择了api表去作为一个驱动表,api_result为被驱动表,所以api表是排在第一位。至于为什么会选择api表作为驱动表,我们等下再说。
<p></p><pre class="brush:go;">2之后与外层查询进行连接查询时,该子查询对应的select_type属性就是MATERIALIZED
<p></p><pre class="brush:go;">possible_key

就是执行中可能会用到的索引,需要注意的是并不是可能用到的索引越多越好,更多的索引意味着查询优化器计算查询成本时需要花费的时间也越多

key


就是实际使用到的索引

key_len


查询优化器最终查询时使用的索引的长度。它是由这三个部分构成的:
1.对于使用固定长度类型的索引列来说,它实际占用的存储空间的最大长度就是该固定值。
2.如果该索引列可以存储NULL值,则key_len比不可以存储NULL值时多1个字节。
3.对于变长字段来说,都会有2个字节的空间来存储该变长列的实际长度。
比如我们这个SQL,最终使用了idx_api_skey_ip_appkey这个索引,其中api的字段类型为varchar(80),数据库使用的字符集是utf8,最大是占三个字节,又因为它是一个变长字段,80 * 3 + 2 = 242,那么就可以看出,实际查询中只使用到了idx_api_skey_ip_appkey这个索引的api列

type

对表的访问方法
——
system
: 当一个表的存储引擎的统计数据是精确的,比如MyISAM,且表中只有一条数据的时候,那么就会使用system
——
const
: 当使用主键索引或者唯一索引进行常数值匹配的时候,为const,需要注意的是,当是联合索引时,要求是要对所有索引字段进行等值常数匹配,否则会为ref
——
eq_ref
: 在连接查询的时候,如果被驱动表是通过主键或者唯一索引进等值匹配时为eq_ref,当是联合索引时,同const一致
——
ref
: 当通过索引进行等值匹配时,就是ref,联合索引不需要对所有字段进行等值匹配
——
ref_or_null
: 对索引列进行等值查找的同时有 OR IS NULL时访问方法为ref_or_null
——
index_merge
: 一般情况一个sql只能走一个索引,但在一些特殊情况下,可能会产生索引合并的情况,这时候就会为index_merge
——
unique_subquery
: 针对在一些包含IN子查询的查询语句中,如果查询优化器决定将IN子查询转换为EXISTS子查询,而且子查询可以使用到主键进行等值匹配的话,就是unique_subquery
——
index_subquery
: 和unique_subquery差不多,只不过子查询使用的索引变成普通索引而已
——
range
: 如果查询中使用到了范围查询,且查询列为索引列,那么可能会使用到range
——
index
: 可以使用索引覆盖,但需要扫描全部的索引记录时,比如有一个联合索引a,b, select a from table where b = ?;这个时候就是index
——
all
: 喜提全表扫描一次

ref

当查询为对索引列进行等值匹配时,与索引列匹配的是什么东西,const-常数列,func-函数......

rows

使用该执行计划,该表预计扫描行数

extra

说一些比较常见的:
——
No tables used
: 当查询语句没有from的时候提示
——
Impossible WHERE
: 查询条件永远为false的时候提示,比如id列不允许为null,查询时使用id is null 就会出现
——
Using index
: 可以使用索引覆盖时提示
——
Using index condition
: 搜索条件中虽然出现了索引列,但却不能使用到索引,比如a为索引,a > 'a' and a like '%zz' 这种
——
Using where
: 使用全表扫描,同时含有where子句 或者 用到索引但where子句中包含非索引列字段的查找
——
Using filesort
: 在排序时不能使用索引列直接进行排序,需要依赖内存或者磁盘去进行排序处理,那么会提示这个
——
Using temporary
: 查询过程中会用到临时表
需要注意的是,
Using index condition
Using where
在我自己测试中发现,和MySQL的版本有关系,5.6和5.7的版本中有不同;另外,当查询中出现
Using filesort
Using temporary
这两个的时候我们可能需要多注意一点,都是比较耗性能的查询,应该尽可能的去优化它

回归到正题,来看这次这个慢SQL的优化,我们可以看出,本次查询选择了以api表作为驱动表,api_result表去作为一个被驱动表。其实一开始看到这个SQL我的预想是认为应该以api_result表作为一个驱动表,那么就可以使用到index_2这个索引,然后再以api_name去连接api表可以使用到api表的index_2索引,所以我尝试加了一个force index(Index_2),测试下:

DESC SELECT SUM(CALL_TIMES) AS TCALLTIMES,SUM(SUCCESS_TIMES) AS TSUCCESSTIMES,SUM(ERROR_TIMES) AS TERRORTIMES FROM API_RESULT AR FORCE INDEX(INDEX_2) JOIN API A ON A.API_NAME = AR.API WHERE AR.COUNT_DATE='2019-08-22' AND A.FREE = '2';

clipboard.png

测试查询很快,但是正常是不建议直接在SQL上加上force index去强制走一个索引的,那还有什么方式去优化它呢?
很明显问题的关键点在于,为什么会选择api表作为一个驱动表?
搜索了一下,原来在内连接的时候,查询优化器会优先选择数据量较少的表作为一个驱动表。
那么一个想法是,我们能不能把api_result表的数据量尽可能的压缩呢?答案是可以做到的,因为本来这次的sql就是要SUM所有的调用次数,那么我们可以先把api_result表的数据先根据api分组统计出来,再根据api连接到api中:

 SELECT SUM(AR.TCALLTIMES), SUM(AR.TSUCCESSTIMES), SUM(AR.TERRORTIMES) FROM API A JOIN (SELECT API,SUM(CALL_TIMES) AS TCALLTIMES, SUM(SUCCESS_TIMES) AS TSUCCESSTIMES, SUM(ERROR_TIMES) AS TERRORTIMES FROM API_RESULT WHERE COUNT_DATE = '2019-08-22' GROUP BY API ORDER BY NULL) AR ON AR.API = A.API_NAME WHERE A.FREE = '2';

clipboard.png

因为API表过滤掉FREE = '2'这个条件后只有400+条记录,而API_RESULT统计出来有2300+条,所以依然还是会选择API表作为驱动表,可以看出API_RESULT使用了想要的INDEX_2索引,通过一个临时表去与API表作连接,执行时间在0.5s左右,比之前的700s左右快了很多,暂时没有更好的想法,如果想要更好的性能,实际应该重新对API_RESULT表进行一个分表处理了。

参考文献

本文参考了掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》—— 小孩子4919,个人觉得是一本很不错的小册,讲的通俗易懂,适合像我这样的小白学习,有兴趣的小伙伴可以去看下


  1. inner join 与 left | right join 不同,内连接因为需要的是两个表都存在的数据,所以驱动表是可以互换的,由查询优化器去选择一个驱动表,而left join 则是左边表为驱动表,右边表为被驱动表,right join 与left join正好相反
  2. 物化是指含子查询的查询语句中,将子查询结果集中的记录保存到临时表的过程

到这里,我们也就讲完了《通过一次慢SQL优化来看EXPLAIN》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于mysql的知识点!

版本声明
本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
关于数据库主键ID的选择关于数据库主键ID的选择
上一篇
关于数据库主键ID的选择
sqli-lab之第零章--环境搭建
下一篇
sqli-lab之第零章--环境搭建
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    514次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    499次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • SEO  AI Mermaid 流程图:自然语言生成,文本驱动可视化创作
    AI Mermaid流程图
    SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
    661次使用
  • 搜获客笔记生成器:小红书医美爆款内容AI创作神器
    搜获客【笔记生成器】
    搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
    671次使用
  • iTerms:一站式法律AI工作台,智能合同审查起草与法律问答专家
    iTerms
    iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
    694次使用
  • TokenPony:AI大模型API聚合平台,一站式接入,高效稳定高性价比
    TokenPony
    TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
    758次使用
  • 迅捷AIPPT:AI智能PPT生成器,高效制作专业演示文稿
    迅捷AIPPT
    迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
    648次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码