索引的使用

建表sql

CREATE TABLE staffs (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR (24)  NULL DEFAULT '' COMMENT '姓名',
  age INT NOT NULL DEFAULT 0 COMMENT '年龄',
  pos VARCHAR (20) NOT NULL DEFAULT '' COMMENT '职位',
  add_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间'
) CHARSET utf8 COMMENT '员工记录表' ;
 
 
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('z3',22,'manager',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('July',23,'dev',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES('2000',23,'dev',NOW());
INSERT INTO staffs(NAME,age,pos,add_time) VALUES(null,23,'dev',NOW());
SELECT * FROM staffs;
 
ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(name, age, pos);

(案例)索引失效

全值匹配我最爱。
最佳左前缀法则。
不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描。
索引中范围条件右边的字段会全部失效。
尽量使用覆盖索引(只访问索引的查询,索引列和查询列一致),减少SELECT *。
MySQL在使用!=或者<>的时候无法使用索引会导致全表扫描。
is not null无法使用索引,但是is null是可以使用索引的
like以通配符开头%abc索引失效会变成全表扫描。
字符串不加单引号索引失效。
少用or,用它来连接时会索引失效。

全值匹配我最爱。

  • 索引 idx_staffs_nameAgePos 建立索引时 以 name ,age,pos 的顺序建立的。全值匹配表示 按顺序匹配的
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July';

在这里插入图片描述
Using index condition指的是查找使用了索引,但是需要回表查询数据

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

在这里插入图片描述

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

在这里插入图片描述

最佳左前缀法则

  • and忽略左右关系。既即使没有没有按顺序 由于优化器的存在,会自动优化。
EXPLAIN SELECT * FROM staffs WHERE age = 25 AND name = 'July';

在这里插入图片描述

  • 当使用覆盖索引的方式时,(select name/age/pos/id from staffs where age=10 (后面没有其他没有索引的字段条件)),即使不是以name开头,也会使用idx_nameAge索引。
EXPLAIN SELECT id FROM staffs WHERE age = 25

在这里插入图片描述

EXPLAIN SELECT pos FROM staffs WHERE age = 25

在这里插入图片描述

  • 既select后的字段 有索引,where 后的字段也有索引,则无关执行顺序。
  • 除开上述条件 才满足最左前缀法则。
EXPLAIN SELECT * FROM staffs WHERE age = 25  #没用到索引

在这里插入图片描述

EXPLAIN SELECT * FROM staffs WHERE name = 'July' and age = 25 # 用到索引

在这里插入图片描述

  • 左前缀"失效"的情况
    有种情况可能会忽略,当表的字段比较少(只有3,4个左右),恰好建索引把所有的字段包含进去了,select *会走覆盖索引的规则
特殊情况
EXPLAIN select * from staffs where name > '33'

在这里插入图片描述

不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

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

在这里插入图片描述

索引中范围条件右边的字段会全部失效

EXPLAIN SELECT * FROM staffs WHERE name = 'July' and age=14 and pos = 'dev'

在这里插入图片描述

EXPLAIN SELECT * FROM staffs WHERE name = 'July' and age>14 and pos = 'dev'

在这里插入图片描述
说明没用到pos字段的索引

尽量使用覆盖索引(只访问索引的查询,索引列和查询列一致),减少SELECT *

EXPLAIN select name,age,pos from staffs where name = 'July' and age = 25 and pos = 'dev' 

在这里插入图片描述

EXPLAIN select * from staffs where name = 'July' and age = 25 and pos = 'dev' 

在这里插入图片描述

EXPLAIN select name,age,pos from staffs where name = 'July' and age > 25 and pos = 'dev' 

在这里插入图片描述

EXPLAIN select name,age,pos from staffs where name = 'July' and age = 25 

在这里插入图片描述

EXPLAIN select name from staffs where name = 'July' and age = 25 

在这里插入图片描述

EXPLAIN select pos from staffs where  age = 25 

在这里插入图片描述

MySQL在使用!=或者<>的时候无法使用索引会导致全表扫描

EXPLAIN select * from staffs where  name <> 'July' 

在这里插入图片描述

EXPLAIN select * from staffs where  name = 'July' and age !=1 

在这里插入图片描述

EXPLAIN select * from staffs where  name = 'July' and age =1 and pos<>'dev'

在这里插入图片描述

is not null无法使用索引,但是is null是可以使用索引的

EXPLAIN select * from staffs where  name is null 

在这里插入图片描述

EXPLAIN select * from staffs where  name is null and age =1 and pos='dev'

在这里插入图片描述

EXPLAIN select * from staffs where  name is not NULL

在这里插入图片描述

EXPLAIN select * from staffs where name = 'July' and age = 1 and pos is not null

在这里插入图片描述
上面有个问题不太懂,type的类型不知道为啥变成range,希望有懂的朋友在评论区说一下

like以通配符开头%abc索引失效会变成全表扫描。

EXPLAIN select * from staffs where name like '%July%'

在这里插入图片描述

EXPLAIN select * from staffs where name like '%July'

在这里插入图片描述

EXPLAIN select * from staffs where name like 'July%'

like ‘abc%’ type 类型为 range ,算是范围,可以使用索引
在这里插入图片描述

EXPLAIN select * from staffs where name like 'July%' and age=1

在这里插入图片描述

问题:解决like’%字符串%'时索引不被使用的方法

  • 如果一定要使用%like,而且还要保证索引不失效,那么使用覆盖索引来编写SQL

字符串不加单引号索引失效

底层隐式转换导致索引失效

EXPLAIN select * from staffs where name = 1

在这里插入图片描述

EXPLAIN select * from staffs where name = '1'

在这里插入图片描述

少用or,用它来连接时会索引失效

EXPLAIN select * from staffs where name = '1' or name = 'July'

在这里插入图片描述

EXPLAIN select * from staffs where name = 'July' and age = 11 or age = 23

在这里插入图片描述

EXPLAIN select pos from staffs where name = 'July' and age = 11 or age = 23 # 覆盖索引

在这里插入图片描述

热身case

  • 建表语句
create table test03(
 id int primary key not null auto_increment,
 c1 char(10),
 c2 char(10),
 c3 char(10),
 c4 char(10),
 c5 char(10)
);
 
insert into test03(c1,c2,c3,c4,c5) values('a1','a2','a3','a4','a5');
insert into test03(c1,c2,c3,c4,c5) values('b1','b2','b3','b4','b5');
insert into test03(c1,c2,c3,c4,c5) values('c1','c2','c3','c4','c5');
insert into test03(c1,c2,c3,c4,c5) values('d1','d2','d3','d4','d5');
insert into test03(c1,c2,c3,c4,c5) values('e1','e2','e3','e4','e5');
 
select * from test03;
 
【建索引】
create index idx_test03_c1234 on test03(c1,c2,c3,c4);
show index from test03;

例子

explain select * from test03 where c1='a1' and c2='a2' and c3='a3' and c4='a4'; 

在这里插入图片描述

 explain select * from test03 where c1='a1' and c2='a2' and c4='a4' and c3='a3'; 

在这里插入图片描述

 explain select * from test03 where c1='a1' and c2='a2' and c3>'a3' and c4='a4';

在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' and c4>'a4' and c3='a3';

在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' and c4='a4' order by c3;

c3作用在排序而不是查找
在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' order by c3;

在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' order by c4; 

出现了filesort
在这里插入图片描述

explain select * from test03 where c1='a1' and c5='a5' order by c2,c3; 

只用c1一个字段索引,但是c2、c3用于排序,无filesort
在这里插入图片描述

explain select * from test03 where c1='a1' and c5='a5' order by c3,c2;

出现了filesort,我们建的索引是1234,它没有按照顺序来,3 2 颠倒了
在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' order by c2,c3;

在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' and c5='a5' order by c2,c3;

用c1、c2两个字段索引,但是c2、c3用于排序,无filesort
在这里插入图片描述

explain select * from test03 where c1='a1' and c2='a2' and c5='a5' order by c3,c2;  

因为c2为常量,所以order by后面不会出现filesort
在这里插入图片描述

explain select * from test03 where c1='a1' and c5='a5' order by c3,c2; 

在这里插入图片描述

explain select * from test03 where c1='a1' and c4='a4' group by c2,c3;

在这里插入图片描述

explain select * from test03 where c1='a1' and c4='a4' group by c3,c2;

在这里插入图片描述

一般性建议

  • 对于单值索引,尽量选择针对当前query过滤性更好的索引。
  • 在选择复合索引的时候,当前query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。(避免索引过滤性好的索引失效)
  • 在选择复合索引的时候,尽量选择可以能够包含当前query中的where子句中更多字段的索引。
  • 尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。

口诀:

  • 带头大哥不能死。
  • 中间兄弟不能断。
  • 索引列上不计算。
  • 范围之后全失效。
  • 覆盖索引尽量用。
  • 不等有时会失效。
  • like百分加右边。
  • 字符要加单引号。
  • 一般SQL少用or。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安澜仙王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值