Mysql的索引使用、索引失效的情况

索引使用

索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。

一、验证索引提升的效率

首先我们先不加索引:
在这里插入图片描述
在这里插入图片描述
查询时间是2秒多,现在我们加上索引并查看:

create index idx_test_agency on test(agency);
show index from test;

Mysql的索引使用、索引失效的情况_第1张图片
这里发现一个问题,创建索引花了10多秒,是因为原本就有300w条数据,所以数据库需要去重建底层的索引结构。
再次查询:只用了0.03s
在这里插入图片描述
然后分析这条语句:
Mysql的索引使用、索引失效的情况_第2张图片
使用了刚才创建的索引,效率提升了很多。

二、索引的使用

(1)创建表和索引

create table `tb_seller` (
	`sellerid` varchar (100),
	`name` varchar (100),
	`nickname` varchar (50),
	`password` varchar (60),
	`status` varchar (1),
	`address` varchar (100),
	`createtime` datetime,
    primary key(`sellerid`)
)engine=innodb default charset=utf8mb4;

# 插入数据
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','华为科技有限公司','华为小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itcast','传智播客教育科技有限公司','传智播客','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('itheima','黑马程序员','黑马程序员','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('luoji','罗技科技有限公司','罗技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('oppo','OPPO科技有限公司','OPPO官方旗舰店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('sina','新浪科技有限公司','新浪官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('xiaomi','小米科技','小米官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('yijia','宜家家居','宜家家居旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');

# 创建一个复合索引
create index idx_seller_name_sta_addr on tb_seller(name,status,address);

(2)索引失效的情况以及避免方式

1. 全值匹配 ,对索引中所有列都指定具体值。

该情况下,索引生效,执行效率高,:

explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';

在这里插入图片描述
可以看到索引已经生效。

2. 最左前缀法则

如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。

explain select * from tb_seller where name='小米科技';
explain select * from tb_seller where name='小米科技' and status='1';
explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';

Mysql的索引使用、索引失效的情况_第3张图片

可以看到,三种情况索引都生效了,现在测试一下索引失效的情况,违背了最左前缀法则:

explain select * from tb_seller where status='1' and address='北京市';
explain select * from tb_seller where name='小米科技'and address='北京市';

Mysql的索引使用、索引失效的情况_第4张图片
可以发现,跳过中间的索引时,最左边的索引还是会生效,但是另外一个就不会生效了。

还有一种情况:当三个索引条件都存在时,与顺序无关,都能生效;

explain select * from tb_seller where status='1' and address='北京市' and name='小米科技';
explain select * from tb_seller where status='1' and name='小米科技' and address='北京市';

Mysql的索引使用、索引失效的情况_第5张图片

3. 范围查询右边的列,不能使用索引 。

explain select * from tb_seller where name='小米科技' and status > '1' and address='北京市';

在这里插入图片描述
这里可以发现:当status是个范围查询的时候,右边的索引就失效了;

4. 不要在索引列上进行运算操作, 索引将失效。

explain select * from tb_seller where substring(name, 3, 2) = '科技';

Mysql的索引使用、索引失效的情况_第6张图片
当我们在截取字段时,做了个运算导致了索引失效了;

5. 字符串不加单引号,造成索引失效。

explain select * from tb_seller where name='小米科技' and status = 1 and address='北京市';

在这里插入图片描述
我们可以看到,当status后面没有加上单引号时,自己本身失效了,右边的索引也失效了。
由于,在查询时,没有对字符串加单引号,MySQL的查询优化器,会自动的进行类型转换,造成索引失效。

6. 尽量使用覆盖索引,避免select *

explain select name, status, address from tb_seller where name='小米科技' and status = '1' and address='北京市';

explain select name, status, address, password from tb_seller where name='小米科技' and status = '1' and address='北京市';

Mysql的索引使用、索引失效的情况_第7张图片
虽然索引都用上了,但是第一条sql的执行效率会高于第二条;

TIP : 
	
    using index :使用覆盖索引的时候就会出现

    using where:在查找使用索引的情况下,需要回表去查询所需的数据

    using index condition:查找使用了索引,但是需要回表查询数据

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

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

explain select * from tb_seller where name='黑马程序员' or createtime = '2088-01-01 12:00:00';

Mysql的索引使用、索引失效的情况_第8张图片
这里索引失效了,如果使用and则有索引的生效。

8. 以%开头的Like模糊查询,索引失效。

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

explain select * from tb_seller where name like '黑马程序%';
explain select * from tb_seller where name like '%黑马程序%';

Mysql的索引使用、索引失效的情况_第9张图片
前者不失效,但是后者失效了,解决这个问题的办法就是进行索引覆盖。

explain select name from tb_seller where name like '%黑马程序%';

在这里插入图片描述

9. 如果MySQL评估使用索引比全表更慢,则不使用索引。

create index idx_address on tb_seller(address);
explain select * from tb_seller where address = '北京市';
explain select * from tb_seller where address = '西安市';

Mysql的索引使用、索引失效的情况_第10张图片
首先是为地址这个字段增加索引,然后进行两个地方的查询,然后发现北京市没有使用索引而西安市则是使用了索引。
我们查看表信息看看:
Mysql的索引使用、索引失效的情况_第11张图片
发现只有一条记录是西安市,其他全是北京市,所以数据库在全表扫描的时候会放弃效率更慢的索引查找方式。

10. is NULL , is NOT NULL 有时索引失效。

explain select * from tb_seller where address is not null;
explain select * from tb_seller where address is null;

Mysql的索引使用、索引失效的情况_第12张图片
但是在上述一样的情况下:如果is null 的全局扫描更快,也既为空数据多的时候,会进行全局扫描,会放弃索引的方式

11. in 走索引, not in 索引失效。

 explain select * from tb_seller where name not in ('阿里巴巴','小米科技');
 explain select * from tb_seller where name in ('阿里巴巴','小米科技');

Mysql的索引使用、索引失效的情况_第13张图片

12. 单列索引和复合索引

尽量使用复合索引,而少使用单列索引 。

create index idx_name on tb_seller(name);
explain select * from tb_seller where name = "阿里巴巴";

Mysql的索引使用、索引失效的情况_第14张图片
首先为name创建单列索引,然后再进行分析sql,发现两者索引都有可能会使用到,但是最后还是选择了最优的复合索引。

三、查看索引使用情况

show status like 'Handler_read%';	

show global status like 'Handler_read%';	

Mysql的索引使用、索引失效的情况_第15张图片

Handler_read_first:索引中第一条被读的次数。如果较高,表示服务器正执行大量全索引扫描(这个值越低越好)。

Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的性能改善不高,因为索引不经常使用(这个值越高越好)。

Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。

Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY ... DESC。

Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应该建立索引来补救。

Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。

四、总结

这些都是基本的索引相关的学习,索引的使用还是需要根据业务需要来进行设计,并不是所有查询都加上索引都是提升性能的。
谢谢大家阅读!!互相学习!
下一篇:Mysql的部分sql优化

你可能感兴趣的:(mysql,mysql,sql)