欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL索引优化(二)

程序员文章站 2022-03-04 19:13:46
...

MySQL索引优化(二)

一、演示索引失效问题

(1)先建立一个staffs表,往其中插入三条数据,其中id为自增的主键
MySQL索引优化(二)

(2)在name,age,pos字段上建立复合索引:

ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(name,age,pos);

(3)现在先列出一些常见的引起索引失效的原因:

1.全值匹配我最爱:

EXPLAIN SELECT * FROM staffs WHERE name='July';

结果如下:
MySQL索引优化(二)

EXPLAIN SELECT * FROM staffs WHERE name='July' AND age=25;

MySQL索引优化(二)

EXPLAIN SELECT * FROM staffs WHERE name='July' AND age=25 AND pos='dev';

MySQL索引优化(二)
以上三个都是ok的

然而,以下语句却变成了全表扫描,没有用到索引

EXPLAIN SELECT * FROM staffs WHERE age=25 AND pos='dev';

MySQL索引优化(二)

EXPLAIN SELECT * FROM staffs WHERE pos='dev';

MySQL索引优化(二)

根据这几个分析,可以引申出下面的结论:
2.最佳左前缀法则
如果索引了多列,要遵守最左前缀法则,指的是查询从索引最左列开始并且不跳过索引中的列

EXPLAIN SELECT * FROM staffs WHERE name='July' AND age=25 AND pos='dev';

MySQL索引优化(二)
上述SQL语句索引未失效,因此可以得出个口诀“排头大哥不能死,中间兄弟不能断”,即索引的第一个列必须要用到,才能确保索引不失效;中间的列不要断开,否则用不到全部的索引。
3.不在索引列上做任何操作(计算、函数、自动或手动类型转换),否则会导致索引失效而转向全表扫描。
如:

EXPLAIN SELECT * FROM staffs WHERE LEFT(name,4)='July';

MySQL索引优化(二)
显然,在索引列上添加了操作后,性能下降了。

4.存储引擎不能使用索引中范围条件右边的列

EXPLAIN SELECT * FROM staffs WHERE name='July' AND age>25 AND pos='dev';

MySQL索引优化(二)
age条件变成了范围,其之后的索引全部失效了。
**5.尽量使用覆盖索引(只访问索引的查询(查询列和索引列一致)),减少select ***

EXPLAIN SELECT name,age,pos FROM staffs WHERE name='July' AND age>25 AND pos='dev';

MySQL索引优化(二)
可见,性能提升。

6.MySQL在使用不等于(!=或< >)的时候无法使用索引会导致全表扫描
MySQL索引优化(二)
7.is null.is not null也无法使用索引
MySQL索引优化(二)
8.like以通配符开头(’%abc…’),索引会失效,变成全表扫描的操作

EXPLAIN SELECT * FROM staffs WHERE name LIKE '%July%';

MySQL索引优化(二)

EXPLAIN SELECT * FROM staffs WHERE name LIKE '%July';

MySQL索引优化(二)

EXPLAIN SELECT * FROM staffs WHERE name LIKE 'July%';

MySQL索引优化(二)
可见,前两条语句索引会失效。于是得出又一个口诀,like %写右边。但是,如果工作中需要用到两边都有%的语句,应该怎么样解决索引不被使用呢?
下面建立一个tbl_user表来进行演示
MySQL索引优化(二)
现在在name和age自动上建立索引

CREATE INDEX idx_user_nameAge ON tbl_user(name,age);

分析以下的SQL语句

EXPLAIN SELECT name,age FROM tbl_user WHERE NAME like '%aa%';

结果如下:
MySQL索引优化(二)
显然使用到了索引idx_user_nameAge ;

下面分析以下SQL语句

EXPLAIN SELECT id FROM tbl_user WHERE NAME like '%aa%';

结果如下:
MySQL索引优化(二)
显然使用了主键索引id;
下面分析以下SQL语句:

EXPLAIN SELECT name FROM tbl_user WHERE NAME like '%aa%';

结果如下:
MySQL索引优化(二)
显然用到了索引idx_user_nameAge
下面分析以下SQL语句:

EXPLAIN SELECT age FROM tbl_user WHERE NAME like '%aa%';

结果如下:
MySQL索引优化(二)
显然使用了索引idx_user_nameAge

如果查询id,name或id,name,age或name,age,索引都是不失效的。
但是如果是以下的SQL语句

EXPLAIN SELECT * FROM tbl_user WHERE NAME like '%aa%';

MySQL索引优化(二)
此时,索引失效。
再分析以下语句:

EXPLAIN SELECT id,name,age,email FROM tbl_user WHERE NAME like '%aa%';

结果如下:
MySQL索引优化(二)
显然,索引失效。
因此,结论就是如果要使用%abc%来做模糊查询,要建立覆盖索引,查询的字段范围不能超过索引所在的字段范围。
9.字符串不加单引号,索引失效
来看看staffs表:
MySQL索引优化(二)
以下两条SQL语句

SELECT * FROM staffs WHERE name=2000;
SELECT * FROM staffs WHERE name='2000';

查询结果相同,如下:
MySQL索引优化(二)
但是根据3中所提到的不要在索引字段上进行任何操作的规则,SELECT * FROM staffs WHERE name=2000; 语句在name字段上进行了类型转换,将2000转成了字符串类型来进行查询,因此索引会失效。
10.少用or,用or来连接时会索引失效
MySQL索引优化(二)
一些小练习:
MySQL索引优化(二)

相关标签: MySQl 笔记