以下代码演示均在linux的mysql服务中运行,我用的是CentOS9

当然依旧使用datagrip或者idea也是可以的

 

create database if not exists bilibili; #创建数据库bilibili use bilibili; #选择bilibili数据库,即可进行下面的代码演示 drop database if exists bilibili; #代码演示结束后删除bilibili数据库。这个小文件全部代码演示完再删 show databases; #查看是否删除完成

 

准备数据

 

 

索引语法

 

查询当前tb_user表有哪些索引

 

 

完成下列的需求

 

-- 1. name字段为姓名字段,该字段的值可以会重复,为该字段创建索引。(常规索引)

-- 验证。查看索引

#对于InnoDB引擎,如果创建索引没有指定索引结构的话,该索引默认的索引结构就是B+树

 

-- 2. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。(唯一索引)

-- 验证。查看索引

 

-- 3. 为profession、age、status创建联合索引。(联合索引,关联这三个字段)

-- 验证。查看索引

 

-- 4. 为email建立合适的索引来提升查询效率。(常规索引)

-- 验证。查看索引

 

 

索引 性能分析 执行频次

 

SQL性能分析

 

SQL执行频率,可以判定出当前数据库丹到底是以插入、更新、删除、查询为主。即查看更删改查在当前数据库的执行频率哪个比较大 当数据库是以增删改为主,那么优化的比重不大。当数据库是以查询为主,那么就要注重性能优化

 

MySQL客户端连接成功后,通过 show [session | global] status 命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的insert、 update、delete、select的访问频次:

 

查询到的结果中,Com_insert、Com_select、Com_update、Com_commit分别表示的是当前数据库的插入、查询、更新、删除的次数

谁的次数多,就可判定为当前数据库以谁为主

 

 

索引 性能分析 慢查询日志

 

注意这节课是必须在linux的操作系统中 !!! 并且开两个会话窗口,一个是mysql>,另一个是[root@localhost ~]#,这两个会话都是同一个linux的MySQL数据库

 

当我们根据上一节课的知识查到当前数据库是以查询select为主,那么我们就要对当前数据库进行优化,我们到底是优化哪些查询SQL,即哪些select语句呢? 我们就可以使用慢查询日志定位出哪些SQL语句的执行效率低,从而对这类SQL语句进行优化

 

慢查询日志 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志 show variables like 'slow_query_log'; #查看慢查询日志是否打开,OFF关闭,ON打开 MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下2条信息:

1、开启MySQL慢日志查询开关

2、设置慢查询日志的时间为2秒,SQL语句执行时间超过两秒,就会视为慢查询,记录慢查询日志

 

配置完毕之后,通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log

 

 

代码演示如下:

 

在[root@localhost ~]#视图下输入如下1行:

 

按键盘上大写的G切换到文本最后一行 按键盘上的a表示插入模式

在弹出来的文本里输入如下3行:

 

按键盘上的esc,然后输入:x,表示保存退出

 

在[root@localhost ~]#视图下输入如下1行,即可找到慢日志文件localhost-slow.log

 

在[root@localhost ~]#视图下输入如下1行,即可查看慢日志文件localhost-slow.log的内容 内容有: 慢日志文件当刚开启时只记录了当前数据库版本、当前数据库端口。后续我们执行select时,就会记录所有执行时间超过指定参数的SQL语句

 

然后在[root@localhost ~]#视图下重启MySQL服务器

 

重新登录MySQL

查看慢查询日志是否打开,OFF关闭,ON打开

 

 

验证如下

 

在[root@localhost mysql]#视图下输入如下1行,表示查看慢日志文件尾部实时输出的内容

 

接着在mysql>视图下输入如下2行,表示执行一条查询语句

 

回到[root@localhost mysql]#视图下,发现并没有新记录出现,原因是我们上面那条查询语句的执行时间在指定参数内,即这上面那条查询语句不是慢语句 当某一条查询语句的执行时间超过我们设置的2秒,这条查询语句就会被记录到慢日志文件里面

 

慢日志文件记录的内容: 哪个用户,哪个主机,耗时,锁了多少行,返回多少条记录,用的哪个数据库,当前操作的时间,执行的哪个SQL语句

 

我们就能够通过慢查询日志定位查询效率低的SQL

 

 

索引 性能分析 Profiles

 

随便执行一些语句

 

温馨提示:这节课用linux终端或xshell,是在不行就用windows的cmd命令行。否则会报红线执行不了

通过上节课的知识我们可以定位出例如哪条查询语句的执行时间超过2秒,即认定该查询语句是慢查询。此时有一个问题,当某条查询语句是1.9秒,

它可以是慢查询语句,但是它不超过2秒就不会被慢查询日志记录,我们就定位不到该1.9秒的查询语句,怎么办呢,就需要使用到这节课的profile操作

show profiles能够在做SQL优化时,帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前MySQL是否支持profile操作:

 

虽然当前数据库支持profile操作,但是profile默认是关闭的,可以通过set语句在session/global级别开启profiling:

 

然后就可以进行profile操作了。profile能够在我们执行SQL时,通过如下指令查看SQL的执行耗时(在命令行操作显示的才正常,可用linux终端或xshell):

 

1、查看每一条SQL的耗时基本情况。可以定位出哪条语句耗时多

 

2、查看指定query_id的SQL语句各个阶段的耗时情况。可以查出某条(查哪条就输入哪条的query_id)耗时多的语句耗时在哪些地方

 

3、查看指定query_id的SQL语句CPU的使用情况.可以查出某条(查哪条就输入哪条的query_id)耗时多的语句耗时在哪些地方,以及CPU耗时

 

如果在dategrip上执行show profiles指令,会多出来很多莫名其妙的数据,建议用linux终端或xshell,是在不行就用windows的cmd命令行

上面第2点的查询某条语句耗时的具体地方,也就是某条语句从开始到结束执行的全过程耗时,过程包括如下

  1. staring...开始执行
  1. checkong...检查权限
  1. Opening...打开对应的表
  1. init进行初始化操作
  1. optimizing进行优化操作
  1. statistios进行统计操作
  1. executing进行执行的操作
  1. end进行执行完毕的操作
  1. waiting进行提交操作
  1. closing...关闭对应的表
  1. ......

 

 

索引 性能分析 explain

 

温馨提示:这节课用linux终端或xshell,实在不行就用windows的cmd命令行。否则有几个命令会报红线执行不了

 

explain执行计划

我们前面学的'执行频次'和'慢查询日志'和'profiles'是以执行时间来判定某条查询语句是否是慢查询语句,实际上这种判定是粗略的判定,并不能真正的

评判SQL语句的性能,我们需要使用explain查看SQL语句的执行计划,才能真正的评判SQL语句的性能。在后面学使用索引的时候,会大量使用explain

explain可以查看某条语句是否用到了索引、表的连接情况、表的连接顺序

 

explain或者desc命令获取MySQL如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序,语法如下

1、直接在select语句之前加上关键字explain / desc

 

我们需要准备之前的3张表,其中学生表和课程表是多对多的关系,另一张是中间表用于维护学生表和课程表之间的多对多关系

 

-- 分别查看上面的3张表数据

 

使用explain和desc的效果是一样的,比较常用的是explain,输出的是一个表格(里面记录了查询计划),其中列头及意思如下:

id(需要用到上面新加的3张表,用这3张表通过SQL语句的查询计划来演示id。id演示比较麻烦,下面那一段都是演示id的,其实id就分两种情况,值相同和值不相同时有不同的执行顺序) select查询的序列号,表示查询中执行select字句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。如下两个需求:

 

(1)使用刚创建的3张表,查询学生的选课情况。多表联查,这里是3张表联查,需要两个条件才能消除无效的笛卡尔积

查询上面那条语句的执行计划。注意能显示出3条数据,重点是id字段,3条数据的id字段都显示1。如果id相同就表示表的执行顺序是从上往下,即3张表的执行顺序是s、sc、c

总结:在id值相同时,即如上多表查询的时候,执行的表的顺序是:表1、表1和表2的中间表、表2

 

(2)使用刚创建的3张表,查询选修了MySQL课程的学生。要求使用子查询

查询选修了id为3的课程的学生,需要去中间表查(中间表没有学生的名字,索引不可能查出学生的名字,只能查出学生的id)

然后根据学生id查出对应的是哪些学生

 

最后把3条散的语句组合起来成为1条

 

查询上面那条语句的执行计划(注意下面那行要在命令行执行,在datagrip执行的话,id分别为1、1、3,是错误的,在命令行执行id是1、1、2、3)才是正确的

 

 

总结:在id值不同时,id值越大就越先执行;id相同就表示表的执行顺序是从上往下。所以上面那行的语句的表按顺序执行分别是如下:

 

c、sc、、s。其中指的是先执行id为2查询,将查询结果保存为临时表,再执行id为1的。也就是是临时表,且

这个临时表就是上面的(select studentid from student_course as sc where sc.courseid = (select id from course as c where c.name = 'MySQL'))

 

select_type:查询类型 表示select的类型,常见的取值有simple(简单表,即不使用表连接或者子查询)、primary(主查询,即外层的查询)、 union(union中的第二个或者后面的查询语句)、subquery(select | where之后包含了子查询)等*/

 

type:连接类型 表示连接类型,性能由好到差的连接类型为null(最好)、system、const(好)、eq_ref、ref、range、index、all(最差)*/

 

(1)当查询的时候不访问任何表,性能才会为null。所以在业务系统中一般不太可能优化为null。null的例子如下

 

(2)当访问系统表的时候,性能才会为system

 

(3)根据主键或唯一索引进行访问,性能才会为const。const的例子如下

 

(4)使用非唯一性索引进行访问,性能才会为ref。ref的例子如下

 

(5)连表查询时使用了唯一索引,性能才会为eq_ref

 

(6)当条件列的索引为primary和unique,性能才会为range

 

(6)使用索引进行访问,性能才会为index。index表示扫描遍历整个索引树,虽然比all快,但是性能也低

 

(7)我们在优化type的时候,尽量把type往前优化,尽量不要出现all。all表示全表扫描,性能低

 

possible_keys:可能用到的索引 显示可能应用在这张表上的索引,一个或多个

 

key:实际用到的索引 实际使用的索引,如果为null,则没有使用索引

 

key_len:索引的长度 表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好

 

rows:扫描的记录数 MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的

 

filtered:符合某条件的记录数百分比。根据主键或唯一索引查的时候,就是100%,根据常规索引查也可能出现100% 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好,最高是100%。共查询了多少行÷共返回多少行×100%=filtered

 

Extra:额外的信息 在前面8个关键字的字段没展示的值,就会在Extra字段里展示

 

 

索引 使用规则 验证索引效率

 

准备数据。为下面导入200万条数据做准备

 

下面导入的是200万条数据,相关sql也就是tb_sku.sql文件我会放出来,我的存放路径在linux的'/root/200wdata/tb_sku.sql'。导入的命令如下:

 

查询tb_sku表的数据量有多少条

 

查询tb_sku表的索引

 

 

验证索引效率,在未建立索引之前,执行如下SQL语句,查看SQL的耗时

 

为查询慢的语句的sn字段创建索引

 

然后再次执行相同的SQL语句,再次查看SQL的耗时

 

查看优化后的语句的执行计划

 

这节课就可以理解为,为一个普通字段创建索引后,当数据量庞大时,能高效的提升查询该字段的效率,总结就是空间换时间

 

 

索引 使用规则 最左前缀法则

 

这节课使用的是tb_user表,这里只学索引使用的第一个原则: 最左前缀原则,主要用于联合索引

 

如果索引了多列,也就是联合索引,那么就要遵守最左前缀法则。最左前缀法则指的是查询从索引最左列开始,并且不跳过索引中的列。如果跳跃了 某一列,索引将部分失效(后面的字段索引失效)

 

查询tb_user表的索引。可查到创建索引时的索引顺序,顺序优先级越上面位置越高。下面讲到的左右,指的是创建索引时的索引顺序,左表示上面位置的索引,右表示下面位置的索引

 

上面那行返回的Column_name字段的profession、age、status就是一组联合索引对应的表字段名。根据最左前缀法则,在进行联合索引查询时,如果要想用到

这3个表字段名的联合索引idx_user_pro_age_sta、idx_user_pro_age_sta、idx_user_pro_age_sta,那么就意味着profession字段一定要有值,不能是null,

并且不能跳过age字段,不然status还是会失效。演示如下

 

上面两条语句的演示,是正常的,查询的时候把3个联合索引idx_user_pro_age_sta都执行了,符合最左前缀法则

 

上面两条语句的演示,是正常的,查询的时候把3个联合索引idx_user_pro_age_sta都执行了,符合最左前缀法则

select * from tb_user where profession = '软件工程'; explain select * from tb_user where profession = '软件工程';#查看这条语句的执行计划,看返回的key列,索引长度总是83,也就是profession字段的索引长度是83

上面两条语句的演示,是正常的,查询的时候把3个联合索引idx_user_pro_age_sta都执行了,符合最左前缀法则

 

在使用索引进行查询时,并且是联合索引查询时,查询的条件一定要包括这组联合索引的第一个表字段名,对于上面来说就是不能少了profession这个表字段名

 

在使用索引进行查询时,并且是联合索引查询时,只要最左边的第一个索引存在,就一定会走索引,但是还跳过了某个索引的话,那么这个被跳过索引的后面索引索引就会失效

 

题目。查询tb_user用户表的数据,条件如下,文下面那条语句在查询时走不走索引

答案,通过explain查看该语句的执行计划,发现返回的key列为idx_user_pro_age_sta,所以上面那条查询走了索引。第一个表字段名,不一定要写最前面,只要写了就行

 

总结: 查询语句走索引的前提是遵循'最左前缀法则',即查询的条件一定要包括这组联合索引的第一个表字段名,不一定要写最前面,只要写了查询条件为

这组联合索引的第一个表字段名就行。如果跳过了某个这组联合索引的表字段名,那么从这个被跳过的表字段名(包含)开始,后面的表字段名的索引都会失效

走索引的好处: 查询效率非常高效

 

注意: 即使索引失效,我们查询的数据也会正确的显示出来,只不过需要的执行时间会多,在查非常庞大的数据时,是很低效率的,所以好好学,别让索引失效

索引的长度根据个人而定,你的跟我的如果不同也很正常,我们可以根据返回的索引总长度推算出具体某个索引的长度,从而就知道哪些索引没走,哪些索引走了

 

 

索引 使用规则 范围查询

 

这节课使用的是tb_user表,这里只学索引使用的第二个原则: 范围查询,主要用于复合索引(也就是联合索引,叫法不同)的范围查询

 

查询tb_user表的索引。可查到创建索引时的索引顺序,顺序优先级越上面位置越高。下面讲到的左右,指的是创建索引时的索引顺序,左表示上面位置的索引,右表示下面位置的索引

 

根据上面那行的执行计划,我们可以知道返回的索引长度总和是88,即走了profession、age索引,没走status索引

 

原因:age > 30 是范围查询,在范围查询右边的索引都会失效,注意age > 30这个范围查询是正常的,失效的是右边的那些字段条件

解决:常用的规避方案就是在业务允许的情况下,使用>=、<=,不要使用>、< 、!=。解决方案的演示如下

根据explain执行计划,上面那行返回的索引总长度是93,即完整的走了3个索引

 

 

索引 使用规则 索引失效情况

 

查看tb_user表的数据

 

查看tb_user表的索引

 

 

-- 第1种情况: 索引列进行运算

 

不要在索引列上进行运算操作(通配符的模糊查询是例外。'%15'、'%01%'不会触发索引。'01%'会走索引,满足最左前缀法则),索引将失效

根据phone字段进行查询的时候,是会走phone索引的

 

根据explain执行计划,验证上面那条语句是否会走phone索引

 

查询手机号最后两位是15的用户,观察phone索引是否会失效。字符串截取,从第10位(包含)开始截取,截取两位

 

根据explain执行计划,验证上面那条语句是否会走phone索引

 

在phone索引使用通配符:'%15'、'%01%'本身是不会触发索引的,属于模糊查询; '01%'本身会走索引,满足最左前缀法则

 

 

-- 第2种情况: 字符串不加引号

 

-- 字符串类型字段使用时,不加引号,索引将失效

 

 

-- 第3种情况: 模糊查询

 

-- 如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效

注意当最左索引是整型时,like '11%'照样会失效,varchar类型不会

 

 

-- 第4种情况: or连接的条件

 

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

开始下面的演示之前,先讲一下我们的age字段,age字段在前几节课设置了复合索引(也就是联合索引,叫法不同),当我们想用age的话,就一定

要用profession字段索引,因为profession是这个联合索引中的最左索引,如果单单只用age索引的话,那么跟没用索引的效果是一样的,我们

就认为age此时不是索引字段

 

解决:为age创建一个常规索引

此时再去执行上面那3条演示语句,索引就都生效啦

 

 

-- 第5种情况: 数据分布影响

 

-- 如果MySQL评估使用索引比全表慢,则不使用索引。简单说就是全表扫描如果都比你使用索引快的话,那么就不让你使用索引

开始下面的演示之前,先讲一下我们tb_user表的数据有24条。并且这24条数据都是非空的,也就是not null

 

当索引字段的条件要求MySQL查询大于或等于该表一半的数据时,MySQL就认为跟我走全表扫描没区别,即使你用索引我也不会用(ps:好傲娇的MySQL)

需要注意的情况,如下

总结: 当MySQL认为它走索引比较快时,才会走索引,不然不走

 

 

索引 使用规则 SQL提示

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

 

1、告诉数据库,我们要使用哪个索引,只是建议,MySQL可能不会采用

例如: explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';

 

2、告诉数据库,不可以使用哪个索引

例如: explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';

 

3、告诉数据库,必须使用哪个索引,强制性

例如: explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';*/

 

 

开始下面的演示之前,先讲一下我们的profession字段,profession字段在前几节课设置了复合索引(也就是联合索引,叫法不同),且正好是最左索引

 

#我们给profession字段再创建一个单列索引

 

#再执行一次查询,观察MySQL会走profession的哪个索引

 

#我们如果不想MySQL走联合索引,指定它走单列索引,怎么做呢。也就是如果当该字段有多个索引,MySQL需要按照我们指定的索引来进行查询。如下

 

#如何让MySQL在查询的时候,不使用我们设置的单列索引

 

#如何让MySQL在查询的时候,强制使用单列索引

 

 

索引 使用规则 覆盖索引&回表查询

 

在进行下面的演示之前,由于tb_user在前面的演示中,字段被添加了很多索引,我们先清除一下后续演示不需要的索引

 

 

覆盖索引

 

什么是 '查询需要返回的字段' : 简单理解就是select后面跟的那个词

覆盖索引指的是一条select查询语句在查询的过程中,使用到了索引,并且查询需要返回的字段,在该索引中已经全部找到了对应的字段值,这类的操作 就称为覆盖查询。前面学的是where之后的条件怎么去规避索引失效。这节课我们学的是查询需要返回的字段怎么去规避索引失效。 在实际业务开发中,尽量使用覆盖索引,较少select *

 

例如下面的4个演示,注意我们主要关注的是select之后的词,from后面的我们不需要过多纠结*/

通过上面的四条演示,可发现前2条的执行计划返回的结果,中的最后一列Extra,前3条语句都是为Using where、Using index。我查的是为null,跟老师对不上

后2条语句的执行计划的Extra列为Using index condition。我查的是为null,跟老师对不上

 

知识小贴士:

1、using index condition: 查找使用了索引,但是需要回表查询数据。也就是出现这个,就说明这条语句回表查询了,回表查询的后果就是查询效率低

2、using where: 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

3、using index: 查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

4、联合索引本质是二级索引,只不过单列存的是一个值加主键,多列是多个值加主键

 

 

主键索引称为聚集索引,也就是id也叫聚集索引。聚集索引的B+树的底部叶子节点的数据是某个id值的一整行数据

 

除主键索引,其他的索引就是二级索引(或叫辅助索引),二级索引的B+树的底部叶子节点的数据是该索引对应的id值

为什么上面查询这id, profession, age ,status四个字段不用回表呢。原因: 是我们在前面几节课把profession, age ,status字段设置了联合索引,联合索引

是属于二级索引(或叫辅助索引),二级索引的B+树的底部叶子节点上的值是id,所以我们在二级索引这里就找到了id, profession, age ,status这四个字段,

把要找的都找完了,就没必要再拿着id主键到一级索引里面查(这步就叫回表查询),也就没有经历回表查询。如果还要求再查一个name字段,由于name字

段不是主键索引,也不是联合索引中的一个,所以要把name字段的值查出来,就必须得经历回表查询

如果没有经历回表查询,也就是只在二级索引的B+树就找到了要找的所有数据,所用到的索引就称为覆盖索引

 

 

什么是回表查询

 

先走二级索引去查,把查询到的结果,拿去聚集索引中查

 

 

总结如下:

 

不回表

 

回表

 

 

 

索引 使用规则 前缀索引

 

讲下面的知识的时候,需要知道例如表的varchar字段存储了很长的值,那我们给这个varchar字段建立索引,就会让索引变得很大 或者说如果需要我们通过文章内容进行查询,这个内容是text类型的字段,存储了上万个字符,我们对这么多字符建立索引,会导致索引变得庞大

 

前缀索引 当字段类型为字符串(varchar, text等)时,有时候需要索引很长的字符串,这会让索引变得很大(索引长度大),查询时,浪费大量的磁盘IO,影响查询效率。 此时可以只将字符串的一部分前缀截取出来,建立前缀,这样可以大大节约索引空间,从而提高索引效率。语法如下

前缀长度 可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性 是1,这是最好的索引选择性,性能也是最好的

 

如何获取tb_user表的email字段的选择性

 

演示如下

 

查看tb_user表的数据

 

查看tb_user表的总记录数,也就是共有多少行

 

查看tb_user表的email字段中不为空的值有多少个

 

查看tb_user表的email字段中不重复的值有多少个,也就是对email字段的值进行去重

 

当截取前10个,查看此时tb_user表的email字段的选择性

 

当截取前9个,查看此时tb_user表的email字段的选择性

 

当截取前6个,查看此时tb_user表的email字段的选择性

 

当截取前5个,查看此时tb_user表的email字段的选择性

 

当截取前4个,查看此时tb_user表的email字段的选择性

 

总结:尽量截取最少的字符作为前缀索引,让选择性尽量接近或等于1,这样查询效率越高,也可降低索引存储的空间

例如上面那里的演示,如果业务要求选择性要尽量高,那么截取前10个是最优的

例如上面那里的演示,如果业务要求平衡选择性和索引体积,也就是让选择性高且索引体积小,那么截取前5个是最优的

截取的越少,索引的体积就越小,不过不能截取的太少,要注意这个'最优'

'此时就出现重复'的后果: 可能会查多个匹配的值,即可能会查出跟我们要查的很相似,但不是我们要查的值,也就是查出来多余的值

当确定好截取5个之后,如何为email字段创建前缀索引(我们命名这个email的前缀索引叫idx_email_5)

 

验证前缀索引

 

查看上面那条语句的explain执行计划,在key_len列的值是23,即我们的前缀索引(idx_email_5)的索引长度为23

 

前缀索引的查询流程如下

1、把表中的id列创建主键索引(也叫聚集索引), 聚集索引在B+树查的是某个id值对应的一整行的数据

2、把email列的每个值的前5个字符截取出来,作为5个前缀索引,前缀索引就是二级索引(也叫辅助索引),二级索引在B+树查的是某个二级索引对应的id值

3、前缀索引必然回表

 

 

索引 使用规则 单列&联合索引

 

单列索引与联合索引

 

单列索引:即一个索引值包含单个列 联合索引:即一个索引包含了多个列

 

#查看tb_user表的索引

 

#查看下面那条语句的执行计划。注意,我们的name和phone字段在前面的学习中设置了单列索引,并且在前面的学习中我们还把phone字段设置成了唯一索引

#上面那行返回的结果的key列只有idx_user_phone,即只有phone索引生效了,也就是查询name的时候,name没有使用索引

 

#为phone和name创建联合索引。由于phone本身是唯一索引,所以创建的phone和name的联合索引idx_user_phone_name必然是唯一索引

 

#再次执行上面的执行计划,查看索引的使用情况

#还是只使用了idx_user_phone索引。执行计划的Extra列为null,表示需要回表查询 #多条件联合查询时,MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询

 

#我们使用前几节课学的SQL提示,告诉MySQL应该使用idx_user_phone_name,然后再次查看执行计划,查看索引的使用情况

#此时使用的就是phone和name的联合索引idx_user_phone_name。执行计划的Extra列为Using index,表示此时用的是覆盖索引,不需要回表查询,效率更高

注意:多条件联合查询时,MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询

创建联合索引的时候,位置谁在前面谁就是最左索引。使用联合索引的时候,位置随便,只要用到了最左索引就行

 

 

索引 使用规则 单列&联合索引

 

为了提高SQL语句的查询效率,应该对什么样的表、什么样的字段建立什么样的索引,就涉及到这节课的设计原则

 

索引设计原则

1、对于数据量较大(超过100w),且查询比较频繁的表建立索引

2、对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字符建立索引。也就是例如在where后面出现的字段建立索引

3、尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高

4、如果是字符串类型的字段,字段的长度比较长的时候,可以对于字段的特点,建立前缀索引(要考虑前缀的区分度)

5、尽量使用联合索引(要遵循最左前缀法则),减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率

6、要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率

7、如果索引列不能存储null值,请在创建表时使用not null约束它。当优化器知道每列是否包含null值时,它可以更好地确定哪个索引最有效地用于查询