MySQL十二:索引分析

转载~

数据库优化是一个很常见的面试题,下面就针对这一问题详细聊聊如何进行索引与sql的分析与优化。

一、执行计划(EXPLAIN)

MySQL 提供了一个 EXPLAIN 命令,它 「可以对 sql语句进行分析,并输出sql执行的详细信息」,可以让我们有针对性的优化。例如:

explain select * from student  where id > 2;

这里需要注意一下版本差异

  • 「MySQL 5.6.3」 MySQL 5.6.3以前只能 EXPLAIN SELECT ;MYSQL 5.6.3以后可以 EXPLAIN SELECT,UPDATE,DELETE
  • 「MySQL 5.7」 MySQL 5.7以前想要显示 partitions 需要使用 explain partitions 命令;想要显示filtered 需要使用 explain extended 命令。在5.7版本后,默认explain直接显示partitions和filtered中的信息。

1.1执行计划详解

「在使用索引的时候首先应该学会分析SQL的执行,使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,可以知道MySQL是如何处理SQL语句」

使用格式:

#explain sql语句  如下:
explain select * from student  where id > 2;

MySQL十二:索引分析

从执行计划输出的结果可以看出,它有很多的字段,每个字段都有自己的含义

  • 「id」 「选择标识符」:在一个查询语句中每个【SELECT】关键字都对应一个唯一的 id。两种例外的情况:
    *
  • 「id相同」优化器对子查询做了 「半连接(semi-jion)优化」时,两个查询的 id 是一样的
explain select * from student  where id in(select id from student  where id > 1);

MySQL十二:索引分析
  • 「id为null」
explain select * from student  union select * from student  where id > 1;

因为 「union会对结果去重,内部创建了一个

MySQL十二:索引分析
  • 「select_type」 「查询的类型」,常用的值如下:查询的类型 类型含义 SIMPLE 简单的select查询,不包含子查询或union查询,是最常见的。 PRIMARY 若查询中包含有子查询,最外层查询会别标记为PRIMARY UNION 若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED SUBQUERY 在SELECT或WHERE列表中包含了子查询 DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生);MySQL会递归执行这些子查询, 把结果放在临时表里。 UNION RESULT 从UNION表获取结果的SELECT DEPENDENT SUBQUERY 在SELECT或WHERE列表中包含了子查询,子查询基于外层 UNCACHEABLE SUBQUREY 无法被缓存的子查询
  • 「table」 输出结果集的表,即查询的表名
  • 「partitions」 匹配的分区
  • 「type」 表示存储引擎查询数据时采用的方式。它 「可以判断出查询是全表扫描还是基于索引的部分扫描」。 常用属性值如下,从上至下效率依次增强。
    *
  • ALL:表示全表扫描,性能最差。
  • index:表示基于索引的全表扫描,先扫描索引再扫描全表数据。
  • range:表示使用索引范围查询。使用>、>=、
  • 「possible_keys」 表示在某个查询语句中,对某个表执行单表查询时 「可能用到的索引列表」
  • 「key」 表示在某个查询语句中,列表示 「实际用到的索引」有哪些。
  • 「key_len」 表示查询使用索引的字节数量。可以判断是否全部使用了组合索引。

    如果键是 NULL,则长度为 NULL。 「使用的索引的长度」。在不损失精确性的情况下,长度越短越好 。

  • 「ref」 当使用索引列等值匹配的条件去执行查询时,ref 列展示 「与索引列作等值匹配的对象」
  • 「rows」 「扫描出的行数(估算的行数)」
    *
  • 如果查询优化器决定使用全表扫描的方式对某个表执行查询时,rows 列就代表预计需要扫描的行数;
  • 如果使用索引来执行查询时,rows 列就代表预计扫描的索引记录行数。
  • 「filtered」 按表条件过滤的行百分比
    *
  • 如果是全表扫描,filtered 值代表满足 where 条件的行数占表总行数的百分比
  • 如果是使用索引来执行查询,filtered 值代表从索引上取得数据后,满足其他过滤条件的数据行数的占比。
  • 「Extra」 Extra 是 EXPLAIN 输出中另外一个很重要的列,各种操作都会在Extra提示相关信息,常见几种如下:
    *
  • Using where:表示查询需要通过索引回表查询数据。
  • Using index:表示查询需要通过索引,索引就可以满足所需数据。
  • Using filesort:表示查询出来的结果需要额外排序,

    数据量小在内存排序,数据量大在磁盘排序,因此有Using filesort 建议优化。

  • Using temprorary:查询使用到了临时表,一般出现于去重、分组等操作。

二、回表查询

在之前《索引基本原理》 中提到InnoDB索引有聚簇索引和辅助索引。

  • 聚簇索引的叶子节点存储行记录,InnoDB必须要有,且只有一个。
  • 辅助索引的叶子节点存储的是主键值和索引字段值

MySQL十二:索引分析

由上图可知: 「通过辅助索引无法直接定位行记录,通常情况下,需要扫两遍索引树。先通过辅助索引定位主键值,然后再通过聚簇索引定位行记录,即回表查询」。性能比扫一遍索引树低。

三、覆盖索引

索引覆盖: 「只需要在一棵索引树上就能获取SQL所需的所 有列数据,无需回表,速度更快」

覆盖索引形式:,搜索的索引键中的字段恰好是查询的字段

实现索引覆盖最常见的方法就是:将被查询的字段,建立到组合索引。

四、最左前缀原则

在之前《索引基本原理》 中提到组合索引的概念,在组合索引的使用中最关键的就是最左前缀原则。

「组合索引使用时遵循最左前缀原则,最左前缀顾名思义,就是最左优先,即查询中使用到最左边的列, 那么查询就会使用到索引,如果从索引的第二列开始查找,索引将失效」

MySQL十二:索引分析

五、索引与排序

5.1排序方式

MySQL查询支持filesort和index两种方式的排序,

  • filesort是先把结果查出,然后在缓存或磁盘进行排序 操作,效率较低。
  • index是指利用索引自动实现排序,不需另做排序操作,效率会比较高。

5.2 排序方式的选择

  • 「使用index方式的排序的场景」
    *
  • ORDER BY 子句索引列组合满足索引最左前列
explain select id from user order by id; //对应(id)、(id,name)索引有效
  • WHERE子句+ORDER BY子句索引列组合满足索引最左前缀
 #对应(age,name)组合索引
explain select id from user where age=18 order by name;
  • 「使用filesort方式的排序的场景」
    *
  • 对索引列同时使用了ASC和DESC
 #对应(age,name)组合索引
explain select id from user order by age asc,name desc;
  • WHERE子句和ORDER BY子句满足最左前缀,但where子句使用了范围查询(例如>、
  • ORDER BY或者WHERE+ORDER BY索引列没有满足索引最左前缀
 #对应(age,name)组合索引
explain select id from user order by name;
  • 使用了不同的索引,MySQL每次只采用一个索引,ORDER BY涉及了两个索引
#对应(name)、(age)两个索引
explain select id from user order by name,age;
  • WHERE子句与ORDER BY子句,使用了不同的索引
#对应(name)、(age)索引
explain select id from user where name='tom' order by age;
  • WHERE子句或者ORDER BY子句中索引列使用了表达式,包括函数表达式
#对应(age)索引
explain select id from user order by abs(age);

5.3排序算法

filesort有两种排序算法:双路排序和单路排序。

  • 双路排序:需要两次磁盘扫描读取,得到最终数据。第一次将排序字段读取出来,然后排序;第二 次去读取其他字段数据。
  • 单路排序:从磁盘查询所需的所有列数据,然后在内存排序将结果返回。
  • 如果查询数据超出缓存 sort_buffer,会导致多次磁盘读取操作,并创建临时表,最后产生了多次IO,反而会增加负担。
  • 解决方案:少使用select *;增加sort_buffer_size容量和max_length_for_sort_data容量。

如果Explain分析SQL时Extra属性显示Using filesort,表示使用了filesort排序方式,需要优化。如果Extra属性显示Using index时,表示覆盖索引,所有操作在索引上完成。

Original: https://www.cnblogs.com/yunlongn/p/16630242.html
Author: 云扬四海
Title: MySQL十二:索引分析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/588792/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 控制反转,依赖注入,依赖倒置傻傻分不清楚?

    通过这篇文章,你将了解到 控制反转(IoC)是什么?「反转」到底反转了什么? Spring和IOC之间是什么关系? 依赖注入(DI)和依赖倒置原则(DIP)又是什么? IOC、DI…

    Java 2023年6月7日
    098
  • java如何获取一个文本文件的编码(格式)信息呢?

    文本文件是我们在windows平台下常用的一种文件格式, 这种格式会随着操作系统的语言不同,而出现其默认的编码不同 那么如何使用程序获取”文本文件”的编码方…

    Java 2023年6月15日
    078
  • 流程与标准

    流程把一件事分解成多个步骤,将涉及到的人都串了起来。有了研发流程,每个人就知道自己要干什么。换句话说,研发流程界定了每个人的职责范围。接着推理,如果发现职责不明确,那就是流程出了问…

    Java 2023年6月16日
    071
  • 观察者模式,无需多线程完成数据监听

    大家好,我们今天来了解一个新的设计模式—— 观察者模式。 观察者模式的思路很简单,它被广泛地用在各种数据监控上。很多时候我们希望监听某个数据的变化,希望一旦获悉它的变化之后立即采取…

    Java 2023年5月30日
    093
  • CTFHub_2017-赛客夏令营-Web-Fast Running(条件竞争、多线程)

    进入场景,显示如下 本题考察条件竞争,需要你改完密码后登录要比系统自动更改密码快 python脚本如下,需要同时开2个线程 __author__ = Serena import t…

    Java 2023年5月29日
    057
  • 用python写十进制与二进制之间转换

    很简单的一段,当练手 def s2e(): e = [0,0,0,0,0,0,0,0] s = int(input("请输入一个十位数:")) for i in…

    Java 2023年6月8日
    0102
  • MySQL 触发器

    触发器是 MySQL 的数据库对象之一,不需要程序调用或手工启动,而是由事件来触发、激活,从而实现执行,包括 INSERT 语句、UPDATE 语句和 DELETE 语句 创建触发…

    Java 2023年6月8日
    0109
  • 【leetcode】42. 接雨水

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height = [0,1,0,2,1,0,1,3,2,1,2…

    Java 2023年6月6日
    078
  • docker:打包node+npm+pm2运行环境镜像

    最近公司有一个外包项目需要在不能连外网的情况下部署node项目到甲方公司内部。直接使用node官网的安装包可以获得node运行环境,但像pm2这种工具要离线装就会比较费劲,所以最终…

    Java 2023年6月5日
    068
  • 戏说领域驱动设计(十九)——外验

    内验是针对领域模型自身的验证,其验证规则也是由领域模型自已来完成,只是触发的时机可能在工厂中也可能在构造函数中。与内验对应的当然就是外验了,这是用于对用户的输入和业务流程的前提或得…

    Java 2023年6月7日
    078
  • Java集合多线程安全

    线程安全与不安全集合 线程不安全集合: ArrayList LinkedList HashMap HashSet TreeMap TreeSet StringBulider 线程安…

    Java 2023年6月7日
    0104
  • VSCODE&shell常用操作git&github

    安装后首次配置git账户 本机首次安装git时,需要配置账户,例如: 查看本地当前安装git版本 git version 配置用户名 –global表示全局,即本地设置一次即可,…

    Java 2023年6月5日
    087
  • js 轮询停止

    clearInterval() posted @2022-09-12 19:36 简单易懂 阅读(14 ) 评论() 编辑 Original: https://www.cnblog…

    Java 2023年6月5日
    0128
  • Kafka 主题解析

    一、主题管理 使⽤ kafka-topics.sh脚本时可用的配置: 选项 说明 –config cleanup.policy compression.type del…

    Java 2023年6月5日
    066
  • 来阿里一年后我迎来了第一次工作变动….

    你怎么不更新啦?怎么最近动态也变少啦?都去干吗了?工作很忙么? 算起来我也阶段性停更一年半了,这一年半不仅是在不断尝试自媒体不同的内容和方向,工作上的巨大转变也推着我去学习尝试了很…

    Java 2023年6月9日
    076
  • Object.keys() 作用

    能便利 Key Object.keys() posted @2022-08-31 16:04 简单易懂 阅读(7 ) 评论() 编辑 Original: https://www.c…

    Java 2023年6月5日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球