没有大数据量的请看这篇https://blog.csdn.net/weixin_44012722/article/details/107974662因为在大数据下的SQL才可以更好的看到优化效果
如果没有看过我这篇博客,可以先看一下这篇对SQL中EXPLAIN关键字数据的分析https://blog.csdn.net/weixin_44012722/article/details/107976412
下面我将通过案例一一介绍索引失效的场景
案例 | 原因 |
---|---|
一 | 给定范围的索引查询range会让后面的索引失效 |
二 | 复合索引最左边的列索引要作为查询索引条件,否则整个复合索引失效,当最左边的列索引作为查询索引条件时,从左到右只要中间哪个列索引不作为查询索引条件时,后面的索引就失效 |
案例二 中的(6)也有说明 排序 和 查找 两个要分清楚 | |
三 | 在索引列上做任何操作(计算,函数,类型转换),会导致索引失效 |
四 | 到查询字段不要写*号,写字段名,*号会使索引失效 |
五 | 索引列作为查找条件,使用不等于(!=或<>)的时候会使索引失效 |
六 | 索引列作为查找条件,使用 is null , is not null 的时候会使索引失效 |
七 | 索引列作为查找条件,使用 like以通配符开头 % 的时候会使索引失效 |
八 | 这里旧的说法 or会让索引失效, 我的MYSQL版本5.5.57,or并不会让索引失效,具体哪个版本会出现这个问题,欢迎指出 |
案例一
1.查询员工首姓为Mary且租用日期大于 1987-02-07 的所有员工并按照生日降序排序取第一个员工数据
# 查询员工首姓为Mary且租用日期大于 1987-02-07 的所有员工并按照生日降序排序取第一个员工数据
explain select * from employees where first_name = 'Mary' and hire_date > date('1987-02-07') order by birth_date desc limit 1
2.创建复合索引
#创建复合索引
create index idx_employess_fhb on employees(first_name,hire_date,birth_date)
3.查看索引
#查看索引
show index from employees
4.explain查看查询语句,并分析
增加了复合索引,可以看到查询类型从all全表扫描变为了range,但是我们已经创建了birth_date字段的复合索引 idx_emplyess_fhb,可是using filesort还是存在, 这 是 因 为 给 定 范 围 的 索 引 查 询 r a n g e 会 让 后 面 的 索 引 失 效 \color{#FF0000}{这是因为给定范围的索引查询range会让后面的索引失效} 这是因为给定范围的索引查询range会让后面的索引失效,因为一条SQL只有一个索引作为查询或排序条件,所以这里后面索引 指的就是 复合索引从左到右顺序
5.删掉索引,重新建立
#删掉索引
drop index idx_employess_fhb on employees
#创建新的索引
create index idx_employess_fb on employees(first_name,birth_date)
6.再EXPLAIN查看查询语句,并分析
可以看到查询类型不但从range变为ref,Using filesort也不见了
案例二
查看员工表员工的信息 根据特定的条件
1.建立 first_name,hire_date,birth_date 三个字段的复合索引
#上面的案例一有旧的索引记得删掉,再创建这个新的
create index idx_employess_fhb on employees(first_name,hire_date,birth_date)
(1)
explain select * from employees where first_name = 'Koblick'
(2)
explain select * from employees where first_name = 'Koblick' and hire_date = date('19780-07-22')
(3)
explain select * from employees where first_name = 'Koblick' and birth_date = date('19780-07-22')
(4)
explain select * from employees where first_name = 'Koblick' and birth_date = date('19780-07-22') and hire_date = date('19780-07-22')
(5)
explain select * from employees where birth_date = date('19780-07-22')
explain select * from employees where hire_date = date('19780-07-22') and birth_date = date('19780-07-22')
(6)
explain select * from employees where first_name = 'Koblick' and birth_date = date('19780-07-22') order by hire_date
(1)-(4)与(5)作对比,我们可以得出结论,复合索引从左到右就好像火车一样,火车头必须要有(就是最左边的列要做为查询索引条件),没有最左边的列索引,整个索引失效
(2) 与 (3)、(1)做对比,我们可以得出结论,当火车头在情况下,如果中间的列索引不作为查询条件,后面的列索引将失效,因为你看 key_len (2)比(3)多3,就是因为(3)中间列索引不作为查询条件,后面的列索引将失效
(6)从中可以得出,查询和排序是两个不同功能,因为我们知道索引是用于查找和排序的,所以因为中间 hire_date作为排序条件,而作为查询条件的first_name ,birth_date,因为复合索引从左到右(first_name ,hire_date,birth_date),而查询和排序是两个不同功能,因为中间hire_date作为排序不是查找,所以后面索引失效,只用到first_name作为索引查找
总结上面两句结论,复合索引最左边的列索引要作为查询索引条件,否则整个复合索引失效,当最左边的列索引作为查询索引条件时,从左到右只要中间哪个列索引不作为查询索引条件时,后面的索引就失效,还有排序和查找两个要分清楚
案例三
explain select * from employees where left(first_name,7) = 'Koblick'
explain select * from employees where first_name = 'Koblick' and DATE_FORMAT(hire_date,'YYYY-MM-dd') = '19780-07-22'
explain select * from employees where first_name=2000
(1)用了left函数 索引失效
(2)用了DATE_FORMAT函数 hire_date索引失效,所以key_len少了3长度
(3)因为 first_name 是 varchar 类型,2000是int类型,他会自动进行一个类型转换 (这里留个问号: 当我 varchar 转 int 类型就不会使索引失效,有早知道的兄弟可以评论告知一下)
案例四
查看员工表 first_name 为Mary
explain select * from employees where first_name = 'Mary'
explain select emp_no,first_name from employees where first_name = 'Mary'
可以看到查询字段不要写号,写字段名,表示索引被作为读取字段进行查找,效率高于号,因为*号尽管包含了索引字段名,但还是失效了
案例五
explain select * from employees where first_name != 'Mary'
explain select * from employees where first_name <> 'Mary'
可以看到在索引列作为查找条件,使用不等于(!=或<>)的时候会使索引失效
案例六
explain select * from employees where first_name is null
explain select * from employees where first_name is not null
可以看到在索引列作为查找条件,使用 is null , is not null 的时候会使索引失效
案例七
explain select * from employees where first_name like '%Mary'
explain select * from employees where first_name like '%Mary'
explain select * from employees where first_name like 'Mary'
可以看到在索引列作为查找条件,使用 like以通配符开头 % 的时候会使索引失效
当然你必须要用到like以通配符开头 % 的情况,你可以使用覆盖索引(查询字段包含索引列),如下
explain select emp_no,first_name from employees where first_name like '%Mary'
explain select emp_no,birth_date from employees where first_name like '%Mary'
注意:
这里提及一下 覆盖索引 ,覆盖索引就是 查询字段 只包含 索引列,SQL就会用到索引去查找数据,包含索引列以外的数据就会覆盖索引失效,接着上面的案例举个例子
explain select emp_no,last_name from employees where first_name like '%Mary'
因为last_name不是索引,索引覆盖索引失效
一键查询淘宝/拼多多内部优惠券,每日大额外卖红包,购物省钱的宝藏工具