1.遵循 联合索引最左列原则
当表中创建了一个 联合索引 idx_name_age_position
案例演示
1.当我们在执行sql 语句:以name 为where 条件时,我们可以用到索引
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';
2.当我们在执行sql 语句:以age为where 条件时,索引就会失效
EXPLAIN SELECT * FROM employees WHERE age = 30;
3.那我们怎么判断用了联合索引的哪几个索引呢?
- 执行以name 为查询条件的
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';
- 执行以 name和age为查询条件的
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22;
- 执行以 name ,age ,position为查询条件的
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
key_len 分析
分析 : key_len 代表的是 索引使用的字节长度
具体字节长度 参考文章 Explain执行计划 https://blog.csdn.net/king_zzzzz/article/details/136801003
创建表的时候,name 为 varchar (24) age int(11) position (20) 且索引字段都不为null
-
若使用 name 索引 ,那么key_len = 24*3+2 =74
-
若使用 name +age 索引, 那么ley_len = key_len(name) + 4 =78
-
若使用 name +age +position 索引, 那么ley_len = key_len(name) + key_len(age ) + 20*3+2 =140
-
创建表的时候,所有的索引字段都不为null
那么每个ley_len = key_len(name) + key_len(age) + key_len(position)
-
若是索引字段允许为null
那么每个ley_len = (key_len(name)+1) + (key_len(age) +1) +( key_len(position) +1)
原因是:如果字段允许为 NULL,需要1字节记录是否为 NULL
2.进行 全值匹配
若是联合索引,那么查询字段越多越好,这样 效率更高(可以判断key_len 是否和联合索引 字节长度判断)
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
3.不建议 在索引列上做任何操作,否则索引会失效
以下sql 的查询条件 在索引树中是 无法定位的,且是无序的
-- 查询name的最左边的两个字符为Li的行
EXPLAIN SELECT * FROM employees WHERE LEFT(name,2) = 'Li';
特例(范围查询)
给时间字段添加个索引
ALTER TABLE employees ADD INDEX idx_hire_time(hire_time)USING BTREE;
- 当我们执行下面sql时,索引会失效,因为我们在索引字段上加了函数
EXPLAIN select * from employees where date(hire_time)='2018-09-30';
- 转化为日期范围查询,就可能会走索引,但具体会不会走,根据表中的数据量来定,若全表扫描的效率> 走索引的效率,就会全部扫描
EXPLAIN select * from employees where hire_time >='2018-09-30 00:00:00' and hire_time <='2018-09-3023:59:59';
4.不能使用联合索引中范围条件右边的列
查询的条件中的联合索引字段 使用了范围查询,那么联合索引中,该范围查询的字段列 右边的不走索引
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager';
key_len =keylen(name) +key_len(age)
原因: 索引树是 有序的 范围查找时 ,该字段是有序的,但是 右边的字段就不是有序的了
5.尽量使用覆盖索引 不需要再回表查询了 减少 select *
- 未使用覆盖索引,进行回表
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
- 使用了覆盖索引,在索引树就可以查找到
EXPLAIN SELECT id,name,age,position FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
6.使用 != 或 <> 不等于查询时,会导致索引失效。
EXPLAIN SELECT * FROM employees WHERE name != 'LiLei';
7.is null ,is not null一般情况下也无法使用索引
mysql 会将null 的所有值放在一起存储
EXPLAIN SELECT * FROM employees WHERE name is null;
EXPLAIN SELECT * FROM employees WHERE name is not null;
8.like查询建议使用xxx%方式匹配,%xxx或者%xxx%索引失效
- 右模糊
EXPLAIN SELECT * FROM employees WHERE name like 'Lei%';
- 左模糊
EXPLAIN SELECT * FROM employees WHERE name like '%Lei';
- 左右模糊
EXPLAIN SELECT * FROM employees WHERE name like '%Lei%';
分析: 索引树中 字符串的排序是从左到右 来进行排序的
优化:对于左右模糊的sql 语句,建议一般采用 覆盖索引来进行优化,
EXPLAIN SELECT id,name,age,position FROM employees WHERE name like '%Lei%';
虽然 是index ,但已经 大于 all 了
9.字符串查询 不加引号 索引也会失效
分析:若是类型不匹配,就可能会使用函数 将 该字段 转换
explain SELECT * from employees where name = 1324;
10.少用 or 或 in ,mysql 不一定会走索引
内部优化器会根据索引树,表大小等来进行评估是否需要走索引
EXPLAIN SELECT * FROM employees WHERE name ='LiLei'or name = 'HanMeimei';
范围查找优化(缩小范围)
先给 age 加一个单值索引
ALTER TABLE `employees` ADD INDEX `idx_age` (`age`) USING BTREE ;
当查找 age 范围 为 1-200 时的数据时
-- 查询age 在1到1000分为内的数据
explain SELECT * from employees where age >1 and age < 1000 ;
分析:
我们要找到1-1000的数据,那么在这棵树书上怎么定位?
- 首先会定位一个age=2在树上的位置 在定位一个age=1999在树上的位置,然后从age=2的节点开始取右边的节点,一直取下去 直到age=1999为止。
- 但是我们表总只有2条数据,mysql觉得这样操作还没有全表扫描快,毕竟一共才几条数据全表扫描反而更快些,所以mysql就去全表扫描了。
- 优化:将范围缩小,就可能用到索引
总结
idx_a_b_c(a,b,c)
建表sql
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`),
KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='员工记录表';
INSERT INTO employees(name,age,position,hire_time)VALUES('LiLei',22,'manager',NOW());
INSERT INTO employees(name,age,position,hire_time)VALUES('HanMeimei',23,'dev',NOW());
INSERT INTO employees(name,age,position,hire_time)VALUES('Lucy',23,'dev',NOW());
标签:匹配,name,age,索引,EXPLAIN,失效,employees,SELECT
From: https://blog.csdn.net/king_zzzzz/article/details/136813110