1 什么情况下需要创建索引?
CREATE TABLE `t_user_index_analyse` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`pos` varchar(10) DEFAULT NULL,
`pay_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_nameAgePos` (`name`,`age`,`pos`)
) ENGINE=InnoDB;
insert into t_user_index_analyse (id,name,age,pos,pay_time) values(1 ,'z3'
,22,'manager','2022-03-13 09:31:34');
insert into t_user_index_analyse (id,name,age,pos,pay_time) values(2 ,'July'
,23,'dev','2022-03-13 09:31:34');
insert into t_user_index_analyse (id,name,age,pos,pay_time) values(3 ,'2000'
,23,'dev','2022-03-13 09:31:34');
1 全局匹配
explain 相关知识
下面这两条SQL语句都是使用了组合索引
explain select * from t_user_index_analyse where name='July' and age=25 and pos='dev';
#这个SQL优化器会优化顺序以使用上索引,但是我们最好还是按照顺序来写
explain select * from t_user_index_analyse where name = 'July';
explain select * from t_user_index_analyse where name='July' and age=25;
第一条SQL语句:
我们可以看到使用了组合索引,key_len是806(最左匹配),ref有三个引用,过滤掉的数据占数据的百分比,比如值为100%,就是没有查到数据。
第二条SQL语句
可以使用了组合索引的一部分,key_len是768(最左匹配),ref中也只是引用了一个字段。
第三条语句:
引用了组合索引的两个字段key_len是773
2 最左法则
#可以使用到索引
explain select * from t_user_index_analyse where name='July';
explain select * from t_user_index_analyse where name='July' and age=25;
#无法使用索引
explain select * from t_user_index_analyse where age=23 and pos='dev'; #没有最左字段
explain select * from t_user_index_analyse where pos='dev'; #没有最左字段
#根据最左匹配使用到了组合索引的一部分
explain select * from t_user_index_analyse where name='July' and pos='dev'; #age字段间断只能使用到一部分
无法使用索引SQL语句:
使用到了组合索引的一部分:
总结:我们使用组合索引的时候要遵循最左匹配原则,组合索引最左的索引如果没有则使用不到索引,如果有最左字段,但是中间字段没有,那么这个时候只会应用最左的字段。
比如(a,b,c) 如果要使用这个索引 a必然不能少, 如果你条件里面是ac,b被跳过了,那么这个时候也只能使用到a,这个与组合索引的存贮有关。因为组合索引是先看a的顺序,在b,c如果都一样看主键的顺序。如果没有最左字段或中间跳字段了这个比较无法进行。
3 不能再索引上做计算
#这个肯定是走不了索引的,因为你的值是动态计算的不知道要从何查起
explain select * from t_user_index_analyse where left(name,4)='July';
explain select * from t_user_index_analyse where name='July' and age>25 and pos='manager';
可以看到走了最左索引name和age这两个字段是可以走组合索引的,age是查询的范围不是等值比较后面的pos就走不了索引了,但是这里可以索引下推,就是后面这个条件可以直接在查询的时候利用起来做一进一步筛选,可以减少服务端筛选的工作量。
5 使用覆盖索引
explain select * from t_user_index_analyse where name='July' and age=25 and pos='manager';
explain select name,age,pos from t_user_index_analyse where name='July' and age=25 and pos='manager';
对比发现explain的结果有所不同,是因为第二条SQL语句组合索引已经存放了所有字段的信息,不用进行回表查询,这就是覆盖索引。
6 索引字段上不要使用不等
# 索引字段上使用(!= 或者 < >)判断时,会导致索引失效而转向全表扫描
explain select * from t_user_index_analyse where name != 'July';
explain select * from t_user_index_analyse where name <> 'July';
很容易理解,不等判断根本无法知道,我下一步应该怎么走,比如我来到树的根节点对比不等这个时候我应该向那条指针走呢?大于这个字符串,小于这个字符串都可能和这个字符串不等,所以没办法在树上进行寻找。
7 索引字段上不使用null
# 索引字段上使用 is not null 判断时,会导致索引失效而转向全表扫描
explain select * from t_user_index_analyse where name is not null;
# 索引字段使用like以通配符开头(‘%字符串’)时,会导致索引失效而转向全表扫描
explain select * from t_user_index_analyse where name like '%July%';
explain select * from t_user_index_analyse where name like '%July';
#这条语句是可以走索引的
explain select * from t_user_index_analyse where name like 'July%';
最后一条语句,因为最左匹配,所以左边的信息可以利用
9 索引字段字符串要加单引号
# 索引字段是字符串,但查询时不加单引号,会导致索引失效而转向全表扫描
explain select * from t_user_index_analyse where name = '2000';
explain select * from t_user_index_analyse where name = 2000;
10 索引字段不要使用or
# 索引字段使用 or 时,会导致索引失效而转向全表扫描
explain select * from t_user_index_analyse where name = 'July' or name='z3';