MySQL知识点总结(二)——explain执行计划、SQL优化

MySQL知识点总结(二)——explain执行计划、SQL优化

  • explain执行计划
    • type
    • possible_keys
    • keys
    • extra
  • SQL优化
    • SQL优化的流程
    • SQL优化技巧
      • 范围查询优化
      • 排序优化
      • 分组查询优化
      • distinct优化
      • 分页查询优化
      • join关联查询优化
      • 排序分页 + 关联查询
      • 分组 + 关联查询 + 排序
      • in与exists的选择
  • join查询原理
    • NLJ
    • BNL

explain执行计划

explain语句用于查看MySQL对某条SQL的执行计划,是我们进行SQL优化时会使用到的一个工具。

在这里插入图片描述

explain包含的所有信息如下。

在这里插入图片描述

其中比较重要的信息是type、possible_keys、keys、extra这几列。

type

这一个信息比较重要,可以通过type列的信息分析出这次查询是否有走索引、走的是唯一索引还是普通索引。

system:表示当前查询的是系统表,也就是表中只有一条记录的表,这种查询是速度最快的,但这是比较极端的情况,因为一般情况下很少有表是只有一条记录的。

const:表示当前查询通过主键索引或者唯一索引定位到表中的唯一一条记录,这种查询的速度也是非常高的,仅次于system查询。

eq_ref:表示本次查询也是走了主键索引或者唯一索引,但是还需要进一步进行表关联查询。

ref:表示本次查询走了普通索引。

range:表示本次查询利用索引进行范围查询。

index:表示本次查询利用了索引进行全索引扫描。

all:本次查询进行了全表扫描,是性能最低的查询。

一般我们要控制我们的查询至少是range以上,如果出现了all,是要进行优化的。

possible_keys

possible_keys是本次查询可能用到的索引,但不是本次查询真正使用的索引,就是有可能使用了,也有可能没有使用。

比如有一个二级索引,但是如果走这个二级索引需要回表才能取到查询需要返回的字段,而MySQL判断回表次数过多,性能不如全表扫描,就有可能放弃走这个二级索引。

keys

keys是本次查询真正使用到的所有,如果possible_keys中有索引出现,而keys中显示没有走该索引,那么就表示存在索引失效的情况,就要分析失效的原因并进行优化。

比如还是上面那一种情况,possible_keys显示本次查询有一个二级索引可以走,但是keys列却显示MySQL没有使用这个二级索引,那么我么经过分析就可以发现原因就是存在大量的回表导致MySQL放弃了走这个索引。于是我们可以优化这个二级索引,把查询需要返回的字段列也加到二级索引中组成一个联合索引,这样MySQL发现不用回表也能取到所有需要返回的字段,就不会再回表进行查询,这时走二级索引查询的性能就会大大提高,MySQL就会选择走二级索引进行查询。

比如我们有一张student表:

CREATE TABLE `student` (`studentno` varchar(10) NOT NULL,`loginpwd` int(11) NOT NULL,`studentname` varchar(40) NOT NULL,`sex` varchar(2) NOT NULL,`gradeid` int(11) NOT NULL,`phone` varchar(20) NOT NULL DEFAULT '0',`address` varchar(30) DEFAULT NULL,`borndate` datetime DEFAULT NULL,`email` varchar(28) DEFAULT NULL,PRIMARY KEY (`studentno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

我们有一个查询:

SELECT borndate, studentname, phone from student where borndate > '1990-06-25 00:00:00';

在没有任何索引时,走的是全表扫描:

在这里插入图片描述

如果我们给borndate列加一个普通索引:

在这里插入图片描述
然后再次查询执行计划:

在这里插入图片描述
发现并没有走我们添加的索引,只是possible_keys出现了我们添加的索引。

然后我们修改一下我们添加的索引,把查询需要返回的字段也加到这个索引里面去。

在这里插入图片描述

然后再次查看查询计划:

在这里插入图片描述
我们发现这次就走了我们的索引,那是因为在二级索引“idx_borndate”中,已经包含了查询需要返回的“borndate”、“studentname”、“phone”三个字段,不需要回表进行查询,性能比起全表扫描大大提升,因此MySQL就会选取该索引进行查询。

extra

这一列是额外信息,也是非常重要的一列。

比如当我们看到extra这一列出现“using index”时,表示我们当前这个查询使用了索引覆盖,比如我们上面的这个例子最后就使用了索引覆盖。

在这里插入图片描述

当我们看到“using filesort”时,表示当前查询的排序使用了文件排序,文件排序性能是比较低的,那就要考虑是否要优化了。

在这里插入图片描述

当我们看到extra列显示“using temporary”时,表示查询使用了临时表。比如select distinct查询一般就会使用到临时表,MySQL会创建一张临时表,利用这张临时表进行去重。

在这里插入图片描述

SQL优化

SQL优化的流程

在工作中,有时会遇到SQL优化。比如我们公司的每一个服务,都有慢查询监控,当某个服务出现慢查询时,监控系统就会通过企业微信的机器人发消息的接口,往群里面发一条慢查询的消息。刚好这个是自己负责的服务的话,那么就会被领导@,然后就要进行对这条慢查SQL优化了。

但是在优化之前,我们应该先读懂这条SQL的逻辑,必要时还要回到这条SQL的出处,代码里面写这条SQL的地方,结合上下文理解这条SQL要实现的功能,这样才能保证我们进行SQL优化之后,不会改变这条SQL原有的功能,以至于改出bug。

然后就可以着手进行优化了。首先看一下这条SQL是否没有走索引,如果是的话,就要考虑给这条SQL的查询添加有效的索引;如果已经有索引了,但是却没有走索引,就要分析索引失效的原因。

在这里插入图片描述

SQL优化技巧

范围查询优化

就是上面的那个覆盖索引优化的例子。

SELECT borndate, studentname, phone from student where borndate > '1990-06-25 00:00:00';

当我们发现查询没有走我们预先创建的二级索引时,一般是由于有大量回表导致的,我们把查询需要返回的字段也添加到索引中,组成一个联合索引,一般就会走索引。

在这里插入图片描述
在这里插入图片描述

排序优化

比如我们有一个查询:

SELECT studentname, phone FROM student ORDER BY studentname DESC;

查询执行计划,走的是文件排序。
在这里插入图片描述

之所以走文件排序,是因为“studentname”字段是无序的,只能开辟一块空间,使用这一块空间进行排序。

如果“studentname”字段的排列是有序的,MySQL是不会使用文件排序的,而给“studentname”字段创建索引,就是使其排列变成有序的方式。

于是,我们给它建立一个联合索引,包含“studentname”和“name”这两列,之所以是联合索引,是因为如果只给“studentname”这一列建立索引的话,那么还是不会走这个索引,因为还要回表去取phone这一列的值。

在这里插入图片描述
查询执行计划,发现使用到了我们创建的索引,并且extra列中的“using filesort”消失了。

在这里插入图片描述

分组查询优化

比如我们有一个查询:

EXPLAIN SELECT gradeid, sum(gradeid) FROM student GROUP BY gradeid;

查看执行计划:

在这里插入图片描述

extra列出现了“Using temporary; Using filesort”,表示即使用了临时表,又有文件排序。

MySQL默认会对分组后的结果进行排序,如果这个排序不是我们需要的,我们可以在SQL语句后面添加“order by null”就可以避免排序。

在这里插入图片描述

而“Using temporary”表示使用到了临时表,之所以用了临时表,是因为要分组的字段(gradeid)在表中是无序的,因此要建立一张临时表,进行分组统计,如果要分组的字段在表中是有序的,那么只需要顺序遍历,就可以完成分组统计。

因此我们添加一个索引:
在这里插入图片描述

再次执行查询计划:
在这里插入图片描述

此时发现分组查询走了索引,extra列中没有了“Using temporary; Using filesort”,而且也不需要添加“order by null”语句。

distinct优化

比如我们还是对“gradeid”这个字段进行去重统计。

SELECT DISTINCT gradeid FROM student;

在这里插入图片描述

发现extra列显示了“Using temporary”,表示MySQL使用了临时表进行去重。这里使用临时表的原因,和上面分组统计的使用临时表的原因是一样的,如果我们给要去重的字段添加索引,就不需要使用临时表进行去重了。

因此我们添加一个索引:
在这里插入图片描述
再次查询执行计划:
在这里插入图片描述
发现“Using temporary”已经没了。

分页查询优化

分页查询的SQL应该是经常出现性能问题的SQL了,因为我们做业务开发的很多场景都有分页查询,是出现频率最高的SQL类型。

比如我们要对人员的出生日期从大到小做倒序排序,然后分页查询人员姓名和出生日期:

	SELECT studentname, borndate FROM student ORDER BY borndate DESC limit 20, 10;

查看执行计划:

在这里插入图片描述
发现做了全表扫描,并且使用了文件排序。这里可以注意一下“rows”这里列,我这个表只有61条数据,这里显示“61”,表示扫描了整张表的61条数据。

这里使用文件排序的原因还是因为borndate字段是无序的,我们给borndate添加索引。

在这里插入图片描述
执行查询计划
在这里插入图片描述
发现还是走了全部扫描加文件排序,这是因为使用“idx_borndate”这个索引有回表查询的成本,MySQL于是放弃该索引。而回表的原因是“idx_borndate”这个索引没有studentname这个字段,而studentname这个字段时查询需要返回的字段,是必须的,但是通过“idx_borndate”这个索引无法取到,因此只能回表。

于是,我们可以通过内连接进行优化。

SELECT studentname, borndate FROM student t1 INNER JOIN (SELECT studentno FROM student ORDER BY borndate DESC limit 20, 10) t2 on t1.studentno = t2.studentno;

再次查看执行计划:
在这里插入图片描述

此时我们发现文件排序没有了,而且MySQL走了我们创建的索引“idx_borndate”。而且扫描行数比原先的61行要少,如果表数据量大的话,这个效果会更加明显。

经过内连接优化后,MySQL首先通过“idx_borndate”索引,找到分页后的要返回的行数据对应的主键studentno,然后扫描这10个studentno,从主键索引中取到对应行记录的studentname和borndate字段。

还有一种优化手段,就是建立联合索引“(borndate, studentname)”,这样就不需要回表也能拿到studentname字段,于是MySQL就会选择走我们的索引。

在这里插入图片描述

查看执行计划
在这里插入图片描述
查询MySQL走了我们的索引,而且SQL也变得简单多了。

join关联查询优化

join查询的优化要记住两点:

  1. 小表驱动大表
  2. 被关联表的关联字段要有索引

小表驱动大表的意思是,数据量小的表作为驱动表,去关联查询数据量大的表。如果此时被关联表的关联字段有索引,那么关联查询的扫描行数相当于小表的扫描行数,性能就会比较高。如果关联查询没有走索引的话,MySQL就会使用“join buffer”进行关联查询,性能就会比较低。join buffer可以理解会在内存中开辟一块空间,把驱动表放到这个内存空间,然后扫描被驱动表的每一行,到这个内存空间中进行遍历匹配。

比如我们除student表以外,还有一个成绩表result,记录学生的考试成绩:

CREATE TABLE `result` (`id` int(11) NOT NULL,`studentno` varchar(10) NOT NULL,`subjectid` int(11) NOT NULL,`score` int(11) NOT NULL,`examdate` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `idx_studentno` (`studentno`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

在没有任何优化的情况下,两张表的关联查询的执行计划如下:
在这里插入图片描述

resutl表有87条记录,student表有61条记录,按理说student表示小表,应该作为驱动表,但是因为result中的studentno字段没有索引,因此MySQL选择result表作为驱动表,这样就可以用上student表中的主键索引,扫描行数就是result表的记录数87条。

如果我们给result表的studentno字段加上索引:
在这里插入图片描述

MySQL就会选择student表作为驱动表,因为student表的数据量更小,更适合作为驱动表,而result表中的studentno字段又有索引,关联查询可以通过result表中studentno字段的索引直接定位,这样扫描的行锁更小,优化到61行。

排序分页 + 关联查询

比如我们要对学生的考试成绩从高到低进行倒序排序,然后分页取排序后的第20~29这十条数据,然后关联查询学生表,返回学生姓名和分数。

SELECT s.studentname, r.score FROM student s JOIN result r ON s.studentno = r.studentno ORDER BY r.score DESC LIMIT 20, 10;

没有任何优化时,执行计划是这样:

在这里插入图片描述

由于需要对result表的score字段进行排序,因此MySQL还是选择了result表作为驱动表,并且score字段没有索引,所以只能使用文件排序,因此extra列出现了“Using filesort”,排序结果再跳过开始的20行取中间10行,到student表中进行关联查询。

此时我们可以给result表添加一个联合索引来进行优化:

在这里插入图片描述

我们修改一下result表中的索引,变成一个联合索引,并且score是索引中的第一个字段,studentno是索引中的字段。这样,因为索引中的score排列是有序的,MySQL就不需要进行文件排序,并且MySQL可以从联合索引中取到关联查询需要的studentno字段,因此,也不需要回表。

查看执行计划:

在这里插入图片描述

我们发现文件排序没有了,并且扫描行数优化成30行,如果表数据量大的话,性能提升是很明显的。

但是要注意的时,这里之所以扫描result表时MySQL走了索引,是因为不需要回表查询result表中需要返回的字段,如果返回结果中包含了result表中的某个字段,并且这个字段是“idx_score_studentno”中没有的,那么由于有回表查询的成本,MySQL就不会走这个索引。比如我们把SQL语句改成查询所有字段“select * from …”,在代码中再从查询结果中取studentname和score这两个字段。

在这里插入图片描述

可以发现MySQL没有走索引,并且使用了文件排序,原因是“idx_score_studentno”索引中不包含result表中需要返回的所有字段,还要进行回表查询,还不如全部扫描。 所以“select *”这种写法真的会导致很多索引优化失效,我们应该时刻记着要按需查询,按需查询不仅可以减少MySQL查询返回结果的大小,而且可以有效的进行索引优化

分组 + 关联查询 + 排序

比如我们要分组统计每个学生的最高得分,然后对分组统计结果进行分页查询

SELECT s.studentname, max(r.score) max_score FROM student s JOIN result r ON s.studentno = r.studentno GROUP BY s.studentno ORDER BY max_score DESC LIMIT 20, 10;

没有做任何优化时,查看查询计划:

在这里插入图片描述

MySQL选择了先对result表进行分组,得到每个人的最高分,然后到student表关联查询得到studentname学生姓名,这样关联查询可以使用到student的主键索引。

我们给result建立一个联合索引:

在这里插入图片描述

这样,MySQL就可以通过result表的索引“idx_studentno_score”得到每个学生的最高分数。

查看执行计划:

在这里插入图片描述

虽然还是出现了“Using temporary; Using filesort”,但是扫描行数以大大降低,并且这次MySQL选择了student表作为驱动表,因此关联查询result表是可以走上索引的,性能还是有所提升的。

但是这种分组、排序、关联、分页全都有的SQL,一般是性能问题高发SQL。如果业务上允许的话,可以通过建立冗余字段进行优化去掉关联查询;或者异步进行分组统计的计算,然后拿一个新的字段去存分组统计的结果,查询时就可以直接查询返回,无需再进行分组统计。

在这里插入图片描述

in与exists的选择

in查询和exists查询,可以互相替代,也能实现相同的查询效果。但是它们的原理有所不同,在不同情况下使用也有所差别。

比如我们现在有一个SQL:

select * from A where A.b_id in (select id from B);

它可以用下面一条SQL替代:

select * from A where exists(select 1 from B where B.id = A.b_id);

in查询是拿in子查询的结果,到外层查询的表中进行匹配;而exists查询是拿着外层查询的结果,在内层查询里面进行匹配,匹配结果返回true或者false,true则保留这条结果,false则丢弃这条结果。

因此,基于“小表驱动大表”的原则,当B表是小表时,适合是用in查询;如果B表较大,而A表较小,那就应该选择exists查询。

在这里插入图片描述

join查询原理

MySQL的join查询有两种算法,一种是Nested-Loop Join(NLJ)算法,一种是Block Nested-Loop Join(BNL)算法。

NLJ

NLJ是当被关联表的关联字段存在索引(并且不失效)时会使用的一种算法。MySQL会扫描驱动表的每一行,然后到被关联表的关联字段对应的索引中进行匹配,返回匹配的数据。

BNL

BNL是当被关联表的关联字段没有索引时会使用的一种算法。MySQL会扫描驱动表,把驱动表(需要返回的字段)放到一个内存区域中(join buffer),然后扫描被驱动的的每一行,到join buffer中进行遍历匹配,返回匹配的记录。

可以看出BNL的性能是比NLJ要差的的,这也是为什么我们在关联查询时一般要保证被关联表的关联字段有索引的原因。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手把手带你Git入门,从下载到精通,常用git命令

文章目录 Git概述什么是GitGit历史Git是什么 为什么要使用Git什么是版本控制系统 Git和SVN对比SVN集中式SVN优缺点 Git分布式Git优缺点 Git工作流程四个工作区域工作流程 Git下载与安装下载window版下载64位软件包安装Git Git基础环境配置设置用户信息查看配置信息 文件的两种状…

ES6.8.6 创建索引配置分词器、映射字段指定分词器、查询数据高亮显示分词结果(内置分词器、icu、ik、pinyin分词器)

文章目录 ES环境内置分词器,以simple分词器示例查询创建索引simple_news,修改分词器为simple插入模拟数据分词查询:返回通过分词查询到的结果、高亮分词分词匹配:写一次示例,其他分词和匹配思路基本一致第一步&#xf…

DMA 和 零拷贝技术 到 网络大文件传输优化

文章目录 DMA 控制器的发展无 DMA 控制器 IO 过程DMA 控制器 传统文件传输性能有多糟糕?如何优化文件传输性能零拷贝技术mmap writesendfileSG-DMA(The Scatter-Gather Direct Memory Access) 零拷贝技术的应用 大文件传输应该用什么方式Pag…

后台管理系统模板搭建/项目配置

1 项目初始化 一个项目要有统一的规范,需要使用eslintstylelintprettier来对我们的代码质量做检测和修复,需要使用husky来做commit拦截,需要使用commitlint来统一提交规范,需要使用preinstall来统一包管理工具。 1.1 环境准备 1…

idea 创建 spring boot

1.创建步骤 2. 编码添加 2.1 这是自动生成的启动函数 package com.example.comxjctest4;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class Application {publi…

MySql的使用方法

一.什么是MySql MySql是一种数据库管理系统,是用来存储数据的,可以有效的管理数据,数据库的存储介质为硬盘和内存。 和文件相比,它具有以下优点: 文件存储数据是不安全的,且不方便数据的查找和管理&#xf…

【3分钟开服】幻兽帕鲁服务器一键部署保姆教程,PalWorld开服联机教程

在帕鲁的世界,你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活,也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活,也可以为你在工厂工作。你也可以将它们进行售卖,或肢解后食用。 想要部署属于自…

从零开发短视频电商 Tesseract OCR识别增强

文章目录 概要图像预处理阶段默认反转图像重新缩放二值化噪音消除膨胀/腐蚀旋转/偏移校正边框缺少边框边框太大扫描边框去除 透明度/Alpha通道 引擎处理阶段语言模型配置提高识别速度词典、单词列表和模式表格识别 使用 Tesseract OCR 的 GUI 和其他项目 原文如下: …

TypeScript实战系列之合理运用类型

目录 介绍any 和 unknownerve 的用途断言type 和 interfacedeclare 关键字的作用联合类型 和 类型守卫交叉类型 介绍 这篇主要介绍下ts 常用的基本类型和一些常用的技巧性技能 any 和 unknow any 和 unknown 是两个类型关键字,它们用于处理类型不确定或未知的情况…

【Sql Server】新手一分钟看懂在已有表基础上修改字段默认值和数据类型

欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Sql Server》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…

力扣日记1.28-【回溯算法篇】93. 复原 IP 地址

力扣日记:【回溯算法篇】93. 复原 IP 地址 日期:2023.1.28 参考:代码随想录、力扣 93. 复原 IP 地址 题目描述 难度:中等 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0&…

IP地址定位技术的巧妙运用:企业网络安全的坚实防线

在当今数字时代,企业网络安全成为了至关重要的议题。面对不断增长的网络威胁,企业不得不采用创新性技术来保护其机密信息和关键系统。IP地址定位技术作为一种强大的工具,为企业提供了一种新颖而高效的网络安全保护手段。 IP地址定位技术简介 …

前端Vue v-for 的使用

目录 ​编辑 简介 使用方式 基本使用 v-for"(item, index)中item和index作用 示例 迭代对象 示例 结果 前言-与正文无关 生活远不止眼前的苦劳与奔波,它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中,我们往往容易陷入…

证券公司怎么选择?福州开股票账户佣金最低是多少?怎么开低佣金账户?

股票交易佣金是指投资者在进行股票交易时,需要向券商支付的手续费。具体的佣金费用根据券商的政策而有所不同,一般分为固定佣金和按比例佣金两种方式。 固定佣金是指交易每一笔固定收取一定金额的佣金,通常适用于较小交易量的投资者&#xf…

github ssh ssh-keygen

生成和使用 SSH 密钥对是一种安全的身份验证方式,用于在你的本地系统和 GitHub 之间进行身份验证。以下是在 GitHub 上生成和使用 SSH 密钥对的基本步骤: 1. 生成 SSH 密钥对 在命令行中执行以下命令来生成 SSH 密钥对: ssh-keygen -C &q…

ATT汇编

指令后缀 AT&T格式的汇编指令有不同的后缀 其中 b表示byte,字节 w表示word,字/两字节 l表示long,32位系统下的long是4字节 q表示quad,意味四重,表示4个字/8字节 寄存器用途 参见 AT&T的汇编世界 - Gemfield…

把数组中的key都取出来然后去重

今日接到一个小需求,一张表有类似这样的数据:(下面是一行) 但是每行的数据,主要是key不一样,我们想把所有的key取出来,并且做个去重。 首先我先在mysql中, SELECT GROUP_CONCAT(RE…

蓝桥杯---九数组分数

1,2,3 ... 9 这九个数字组成一个分数,其值恰好为1/3,如何组法? 下面的程序实现了该功能,请填写划线部分缺失的代码。 注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。 代码 public class _05九数组分数 {public static void test(int[] x){int a …

Linux, Certbot快速申请免费https证书

linux环境. 更新apt,为了能正确的下载certbot apt update 安装certbot apt install certbot 如果之前nginx已经开启着了,先关掉,防止端口占用 nginx -s stop 运行certbot开始获取证书文件 certbot certonly 输入1直接回车,意思就是让certbot模拟一个web服务器执行下面的…

探秘Photoshop | 一站式了解所有相关信息

Photoshop是迄今为止世界上最强大的图像编辑软件,它已成为许多涉及图像处理的行业标准。软件技术一天行千里, Photoshop也在不断更新,从1990年开始发布, photoshop1.0到最新的 2018Photoshop... 几乎每隔一年,Photosho…