MySQL索引3——Explain关键字和索引使用规则(SQL提示、索引失效、最左前缀法则)

目录

Explain关键字 索引性能分析

Id ——select的查询序列号

Select_type——select查询的类型

Table——表名称

Type——select的连接类型

Possible_key ——显示可能应用在这张表的索引

Key——实际用到的索引

Key_len——实际索引使用到的字节数

Ref    ——索引命中的列或常量

Rows——预计select语句要检查的行数

Filtered——返回结果的行数占读取行数的百分比

Extra——显示额外的信息

索引的使用规则

SQL提示

最左前缀法则

索引失效情况

索引的设计原则


Explain关键字 索引性能分析

Explain可以应用于SELECT、DELETE、INSERT、REPLACE、UPDATE语句

通过Explain关键字可以看到SELECT语句的执行计划,即可以查看到MySQL如何处理SELECT语句,通过Explain显示的结果来决定如何优化

具体的作用有

  1. 查看表的读取顺序
  2. 查看此语句可以使用哪些索引
  3. 此语句实际使用了哪些索引
  4. 查看此语句查询了多少行数据

explain语法

在任意的SELECT语句之前加上关键字 Explain或者Desc

EXPLAIN SELECT * FROM 表名;

使用Explain后返回的结果

查询结果的各个字段

Id ——select的查询序列号

表示查询中SQL执行的顺序;id相同时的执行顺序为从上到下;id不同时值越大越先执行

对于单表查询,查询一次一般会产生一个id的一行信息

explain select * from user;

对于多表查,查询一次一般会产生相同id的多行信息

 explain select * from career,user where career.id = user.career_id;

对于子查询,查询一次一般会产生不同id的多行信息

explain select * from user where user.career_id = (select id from career where id=1);

Select_type——select查询的类型

常见的取值有

SIMPLE:简单的select查询类型;查询语句中不包含子查询或UNION

PRIMARY:当查询中包含子查询或UNION时,即外层的查询为此查询类型

SUBQUERY:在SELECT或WHERE中包含了子查询时会被标记为此查询类型

DERIVED:在FROM列表中包含的子查询被标记为此查询类型(MySQL会将此子查询的查询结果作为临时表—派生表)

explain

select * from

 (select origo,count(*) as number from staff1 group by origo) as emp    

 where emp.number > 2; #根据居住地分组,并查询居住地人数大于2的(派生表的别名为emp)

UNION:在UNION中的第二个和随后的SELECT语句被标记为UNION(如果UNION被FROM子句中的子查询包含,则它的第一个SELECT会被标记为DERIVED)

explain

select origo,count(*) as number  from staff2 group by origo

union

select origo,count(*) as number  from staff1 group by origo;

explain

select origo,count(*) as number  from staff2 group by origo

union

select * from (select origo,count(*) as number from staff1 group by origo) as emp  where emp.number > 2;

 UNION RESULT:表示对应UNION的结果(UNION和UNRESULT一般会成对出现)

Table——表名称

显示这一行的数据是关于哪张表的,显示结果可能为表的名称、<derivedX>、<unionX1,X1>等

<derivedX>

当from子句中有子查询时,table列为<derivedX>的格式(x为id值),对应子查询返回的临时表(派生表)

<unionX1,X1>

当存在union时,union result的table列为<unionX1,X1>的格式;X1和X2表示参与union的表的id序号

Type——select的连接类型

select的连接类型是查看索引执行情况的一个重要指标,就是MySQL如何查找数据表中的记录

连接类型的性能由好到差为NULL、system、const、eq_ref、ref、fulltext、ref_or_null、index_merge、unique_subquery、index_subquery、range、index、all

重点关注的是:NULL、system、const、eq_ref、ref、range、index、all

在优化时尽量优化为性能好的(当查询时不查询任何表时才会出现NULL)

主键或唯一索引查询会出现const,使用非唯一性索引查询时会出现ref

一般我们最好保证查询时type达到range、ref级别

All和Index都是读全表,只是Index读的是索引树,All读的是数据表

不同连接类型代表的含义(通过Staff1表来模拟现象)

Fulltext:       当查询使用到全文索引时的连接类型

Ref_or_null: 类似于ref,也是非唯一性索引扫描;不过MySQL还会扫描哪些行包含了NULL

Index_merge: 表示使用了索引合并优化(即一个中使用到了多个索引)

Unique_subquery:类似于eq_ref,唯一性索引扫描;但是使用了IN查询,并且子查询查询字段为主键或唯一索引

Index_subquery:  类似于unique_subquery;不过子查询查询字段为非唯一索引

Null:   查询时不查询任何表(MySQL在优化阶段会分析查询语句,以此来判断是否需要访问表)或者在查询的值在此字段找不到,并且此字段建立了唯一索引

explain select min(id) from staff1; #查看主键的最小id

System:表只有一行记录;是Cost的特殊情况,平时不会出现可忽略

Const: 表示通过索引一次就找到了要查询的记录(一般存在于单表查询时,主键或唯一索引作为查询条件)

explain select * from staff1 where number=2021004;

 Eq_ref: 唯一性索引扫描;对于每个索引键,表中只有一条记录与之匹配;(一般存在于多表查询时,使用主键或唯一索引扫描作为查询条件)

explain select s1.*,a1.* from staff1 s1, account a1 where s1.id = a1.id;

 Ref:      非唯一性索引扫描;返回匹配某个单独值的所有行,可能会找到多个符合条件的行,属于查找和扫描的混合体(用于常规索引、联合索引情况)

explain select * from staff1 where origo='重庆';

Range:范围查询;当给一个字段添加索引之后,使用范围作为此字段的条件进行数据查询时的连接类型(般就是在where语句中出现了between、<、>、in等的查询)

explain select * from staff1 where number>2021001;

Index:index类型值遍历索引树(通过遍历索引树来查找数据,需要查找的字段都已经建立了索引-主键索引、唯一索引、常规索引等)

explain select id,number from staff1;

ALL:将遍历全表已找到匹配的行,没有使用索引

Possible_key ——显示可能应用在这张表的索引

该值为一个或多个

此字段显示的索引不一定会被查询使用到,可能会出现索引失效的问题

当Select语句发现可以使用多个索引的时候,可以通过SQL提示来建议Mysql语句使用指定的索引,可以避免SQL使用了性能比较低的索引(例如如果同时存在唯一索引和常规索引,可以建立SQL使用唯一索引)

Key——实际用到的索引

如果没有使用索引,则为NULL

哪些情况会导致有可用索引但是实际上没有使用到索引呢?

1、对于联合索引来说,没有遵守最左前缀法则

2、范围查询时使用到>或<,会导致范围查询右侧的列索引失效

3、在Where之后的索引列上进行运算操作(包含函数、比较运算符、谓词等)

4、字符串类型字段的值使用时,如果不加引号,存在隐式类型转换,索引将失效

5、当对头部进行模糊匹配时,索引会失效(即Like(%字符)或者Like(_字符))

6、用or分隔开的条件,如果or前条件中的列有索引,而后面的列中没有索引,那么or前面的索引不会被用到

7、数据分布影响;如果MySQL评估使用索引查询比全表查询更慢,则不使用索引,使用全表查询

如何规避索引失效呢?————具体在索引的优化介绍

1、联合索引遵守最左前缀法则,在创建联合索引时尽量将使用频率高的字段放在最左端

2、在范围查询时尽量使用过>=或者<=来规避范围查询

3、尽量不对索引列进行运算操作

4、在使用属于字符串类型的字段时,需要对其值加上引号

5、尽量使用尾部模糊匹配来代替头部模糊匹配;当对尾部进行模糊匹配时,则索引不会失效(即Like(字符%)或者Like(字符_))

6、只有当or前后都是用到索引时,索引才会失效

Key_len——实际索引使用到的字节数

表明了在索引中使用的字节数,通过此值可以大致估算出使用了索引中的哪些列

Key_len的计算规则

当字段允许为Null时,比不允许为Null大1个字节

不同的数据类型,占用的字节数时不同的,详情可以参考以下官方文档(介绍的是不允许为空的情况)

MySQL :: MySQL 8.0 Reference Manual :: 11.7 Data Type Storage Requirements

对于字符串数据类型来说,其占用的字节数还跟使用的字符编码有关

GBK               2字节

UTF8             3字节

ISO8859-1     1字节

GB2312         2字节

UTF-16          2字节

Ref    ——索引命中的列或常量

表进行数据查找时使用字段、常量、函数的结果等

常量:           const

空:              NULL

字段:           数据库名.表名.字段名

函数的结果:func(如果要想查看是哪个函数,可以在Explain语句后跟上SHOW WARNING语句)

explain select origo from staff1 where origo='重庆';

explain select * from staff1 where id in (select id from staff1 where id > 2);

Rows——预计select语句要检查的行数

mysql估计要读取并检查的行数;并不是结果的行数

在innoDB引擎中的表中,是一个估计值,不是很准确

Filtered——返回结果的行数占读取行数的百分比

该值越大越好

Extra——显示额外的信息

通过此字段显示的额外信息,也可以进行查询的优化(不同MySQL版本显示的内容可能会有些许差别)

Using Index:查找使用了索引,并且返回所需要的数据在该索引列中就可以找到(无需回表查询)

Using Where:先读取整行数据,再按照Where条件进行查询(符合就留下,不符合则丢弃)

Using Join Buffer:表示查询使用了连接缓冲(多用于多表连接查询)

Using Index Condition:查找使用了索引,但是需要回表查询数据—此种情况一般需要优化(可以使其满足覆盖索引条件来避免回表查询)

Using Temporary:查找使用了临时表(多见于group by语句)--此种情况一般需要优化(优先通过建立索引解决)

Using Filesort:通过表的索引或者全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫FileSort排序(多见于order by语句)----此种情况一般需要优化(优先通过建立索引解决)

一般需要将Using Filesort、Using Temporary、Using Index Condition 等优化为Using Index


索引的使用规则

通过遵守索引的使用规则,避免索引失效;并且可以手动选择索引进行索引查询;使得索引的到最大利用

SQL提示

是优化数据库的一个重要手段,就是在SQL语句中加入一些人为的提示来达到优化操作的目的

SQL提示的字段

USE INDEX            建议数据库使用哪个索引(当一列属于多个索引类型式,建议此列使用哪种类型的索引,MySQL可能不会采用此建议)

IGNORE INEDX     告诉数据库不要用哪个索引      

FORCR INDEX       告诉数据库必须使用哪个索引

SQL提示的格式

SELECT 字段列表 FROM 表名 USE INDEX (索引名称) WHERE 判断条件; 

情景模拟

针对上述表,我们为origo、age创建了联合索引,现在我们再针对origo创建一个常规索引

 explain select origo from staff1 where origo='重庆' and age > 18; #此时我们查询此语句走的是联合索引  我们可以通过语句修改使其走单列索引

explain select origo from staff1 use index (as_origo) where origo='重庆' and age > 18;

最左前缀法则

主要针对联合索引,如果索引为联合索引,则要遵守最左前缀法则

最左前缀法则的要求

在使用联合索引进行查询时,查询从联合索引的最左列开始,并且不跳过索引中的列,可以跳过最右边的一列或多列;

在查询时,如果中途跳过了联合索引中的某一列,索引部分失效(此列之后的列索引失效),即无法进行索引查询,只可以进行全文查询

在查询时,如果最左边的列不存在,则不走索引,走全文扫描(即进行联合查询时必须包含最左列)  在查询时不用关心顺序,只要存在就可以了

create index as_origo on staff1(origo,age,name); #创建时由左到右创建,左边一般为查询频率高的

explain select * from staff1 where origo='重庆';

explain select * from staff1 where origo='重庆' and age = 22 ;    #查询时,也是从左到右查询;此时使用了索引

explain select * from staff1 where origo='重庆' and name='老六';   #此时origo使用了索引,name没有使用索引(通过key_len使用索引的字节数判断)

explain select * from staff1 where age = 22 ;   #此时没有使用索引(没有包含origo字段)

索引失效情况

范围查询

在联合索引中,出现范围查询(>或<)时,范围查询右侧的列索引失效

尽量使用过>=或者<=来规避范围查询

运算操作

在索引列上进行运算操作时,索引列将失效;运算包括使用函数、比较运算符、谓词等

字符串数据类型

字符串类型字段使用时,如果不对其值加引号,则存在隐式类型转换,索引将失效

Like字段模糊查询

当对尾部进行模糊匹配时,则索引不会失效(即Like(字符%)或者Like(字符_))

当对头部进行模糊匹配时,索引会失效(即Like(%字符)或者Like(_字符))

or连接条件

用or分隔开的条件,如果or前/后的条件中的列有索引,而后/前面的列中没有索引,那么or前/后面的索引不会被用到;

只有当or前后都是用到索引时,索引才会失效

数据分布影响

如果MySQL评估使用索引查询比全表查询更慢,则不使用索引,使用全表查询(一般用于大小判断的时候会出现)

由于B+树是顺序链表,当第一个叶子就符合或者前几个叶子就符合时,后面的叶子就必然也符合;此时MySql就判断使用全表查询更快,就会不适用索引,使用全表查询了

即:当要查询的结果占全表很大的比例时,可能就进行全表查询了

索引的设计原则

  1. 针对数据量较大(100多万数据及以上)、且查询比较频繁的表建立索引(很少查询,没有必要建立索引
  2. 针对于常作为查询条件(Where)、排序(Order By)、分组(Group By)操作的字段建立索引
  3. 尽量区分度高的列作为索引,尽量建立唯一索引;区分度越高,使用索引的效率越高
  4. 如果是字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引
  5. 尽量使用联合索引,减少单列索引;查询时联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
  6. 控制索引的数量,索引越多,维护索引结构的代价也就越大,会影响增删改的效率
  7. 如果索引列不能存储Null,就在创建表时使用NOT NULL约束此字段;当MySQL优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询

总结

1、查询效率不高,首先使用explain分析:

如果发现没有索引,可以创建索引

如果发现是单列索引,要注意是否存在索引失效

如果发现是联合索引,要注意是否遵守最左匹配原则

2、尽可能地使得查询语句扫描更少地行数、表、列

3、如果对字符串创建了索引,尽可能减少字符串的长度(即为较短的字符串建立前缀索引)

4、尽量使得索引查询满足覆盖索引,避免回表查询

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

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

相关文章

【Linux】五、进程

一、冯诺依曼体系结构 存储器&#xff1a;指的是内存&#xff1b; 输入设备&#xff1a;键盘、摄像头、话筒&#xff0c;磁盘&#xff0c;网卡&#xff1b; 输出设备&#xff1a;显示器、音响、磁盘、网卡&#xff1b; 中央处理器&#xff08;CPU&#xff09;&#xff1a;运算器…

【开源项目--稻草】Day04

【开源项目--稻草】Day04 1. 续 VUE1.1 完善VUEAJAX完成注册功能 Spring验证框架什么是Spring验证框架使用Spring-Validation 稻草问答-学生首页显示首页制作首页的流程开发标签列表标签列表显示原理 从业务逻辑层开始编写控制层代码开发问题列表开发业务逻辑层开发页面和JS代码…

HTML5 Canvas(画布)

<canvas>标签定义图形&#xff0c;比如图表和其他图像&#xff0c;你必须用脚本来绘制图形。 在画布上&#xff08; Canvas &#xff09;画一个共红色矩形&#xff0c;渐变矩形&#xff0c;彩色矩形&#xff0c;和一些彩色文字。 什么是 Canvas&#xff1f; HTML5<c…

机器学习深度学习——序列模型(NLP启动!)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——卷积神经网络&#xff08;LeNet&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习&&深度…

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存二级缓存

Mybatis一级缓存&二级缓存 概述一级缓存特点演示前准备效果演示在同一个SqlSession中在不同的SqlSession中 源代码怎么禁止使用一级缓存一级缓存在什么情况下会被清除 二级缓存特点演示前准备效果演示在不同的SqlSession中 源代码怎么关闭二级缓存 一级缓存&#xff08;Spr…

Docker 安装 Tomcat

目录 一、查看 tomcat 版本 二、拉取 Tomcat Docker 镜像 三、创建 Tomcat 容器 四、访问 Tomcat 五、停止和启动容器 一、查看 tomcat 版本 访问 tomcat 镜像库地址&#xff1a;https://hub.docker.com/_/tomcat&#xff0c;可以通过 Tags 查看其他版本的 tomcat; 二、拉…

Android Studio 的Gradle版本修改

使用Android Studio构建项目时&#xff0c;需要配置Gradle&#xff0c;与Gradle插件。 Gradle是一个构建工具&#xff0c;用于管理和自动化Android项目的构建过程。它使用Groovy或Kotlin作为脚本语言&#xff0c;并提供了强大的配置能力来定义项目的依赖关系、编译选项、打包方…

HCIA---OSI/RM--开放式系统互联参考模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.OSI--开放式系统互联参考模型简介 OSI开放式系统互联参考模型是一种用于计算机网络通信…

解密Redis:应对面试中的缓存相关问题2

面试官&#xff1a;Redis集群有哪些方案&#xff0c;知道嘛&#xff1f; 候选人&#xff1a;嗯~~&#xff0c;在Redis中提供的集群方案总共有三种&#xff1a;主从复制、哨兵模式、Redis分片集群。 面试官&#xff1a;那你来介绍一下主从同步。 候选人&#xff1a;嗯&#xff…

Flutter iOS 集成使用 fluter boost

在 Flutter项目中集成完 flutter boost&#xff0c;并且已经使用了 flutter boost进行了路由管理&#xff0c;这时如果需要和iOS混合开发&#xff0c;这时就要到 原生端进行集成。 注意&#xff1a;之前建的项目必须是 Flutter module项目&#xff0c;并且原生项目和flutter m…

Baumer工业相机堡盟工业相机如何通过BGAPISDK获取相机接口数据吞吐量(C++)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里函数来获取相机当前数据吞吐量&#xff08;C&#xff09; Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在BGAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过BGAPI SDK获取数…

【微信小程序】van-uploader实现文件上传

使用van-uploader和wx.uploadFile实现文件上传&#xff0c;后端使用ThinkPHP。 1、前端代码 json&#xff1a;引入van-uploader {"usingComponents": {"van-uploader": "vant/weapp/uploader/index"} }wxml&#xff1a;deletedFile是删除文件函…

Xilinx FPGA电源设计与注意事项

1 引言 随着半导体和芯片技术的飞速发展&#xff0c;现在的FPGA集成了越来越多的可配置逻辑资源、各种各样的外部总线接口以及丰富的内部RAM资源&#xff0c;使其在国防、医疗、消费电子等领域得到了越来越广泛的应用。当采用FPGA进行设计电路时&#xff0c;大多数FPGA对上电的…

【计算机网络】12、frp 内网穿透

文章目录 一、服务端设置二、客户端设置 frp &#xff1a;A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet。是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且…

VUE框架:vue2转vue3全面细节总结(5)过渡动效

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人_python人工智能视觉&#xff08;opencv&#xff09;从入门到实战,前端,微信小程序-CSDN博客 最新的uniapp毕业设计专栏也放在下方了&#xff1a; https://blog.csdn.net/lbcy…

ES6 数组的用法

1. forEach() 用来循环遍历的 for 数组名.forEach(function (item,index,arr) {})item:数组每一项 , index : 数组索引 , arr:原数组作用: 用来遍历数组 let arr [1, 2, 3, 4]; console.log(arr); let arr1 arr.forEach((item, index, arr) > {console.log(item, index…

HTTP——八、确认访问用户身份的认证

HTTP 一、何为认证二、BASIC认证BASIC认证的认证步骤 三、DIGEST认证DIGEST认证的认证步骤 四、SSL客户端认证1、SSL 客户端认证的认证步骤2、SSL 客户端认证采用双因素认证3、SSL 客户端认证必要的费用 五、基于表单认证1、认证多半为基于表单认证2、Session 管理及 Cookie 应…

Android network — iptables四表五链

Android network — iptables四表五链 1. iptables简介2. iptables的四表五链2.1 iptables流程图2.2 四表2.3 五链2.4 iptables的常见情况 3. NAT工作原理3.1 BNAT3.2 NAPT 4. iptables配置 本文主要介绍了iptables的基本工作原理和四表五链等基本概念以及NAT的工作原理。 1. i…

RocketMQ Learning

一、RocketMQ RocketMQ的产品发展 MetaQ&#xff1a;2011年&#xff0c;阿里基于Kafka的设计使用Java完全重写并推出了MetaQ 1.0版本 。 2012年&#xff0c;阿里对MetaQ的存储进行了改进&#xff0c;推出MetaQ 2.0&#xff0c;同年阿里把Meta2.0从阿里内部开源出来&am…

杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)

文章目录 01 准备工作02 &#xff08;可选&#xff09;配置交换内存03 编辑docker-compose.yml04 启动并修改配置05 nginx反向代理06 &#xff08;可选&#xff09;修改配置文件07 访问并登录 01 准备工作 最近想自建一个gitlab服务来保存自己的项目&#xff0c;于是找到gitla…