在mysql5.7中,一般为了查询速度,通常会引入索引,但是有时候我们的索引并没有引起效果,所以整理下一般在什么情况下会引起索引失效,即索引没有被使用。
一.发生隐式类型转换
现在我们有一个名为t_test的数据表,他的字段与数据存储类型如下所示,并且在字段phone字段建立索引:
名称 | 类型 | 长度 |
id | bigint | 0 |
name | varchar | 10 |
phone | varchar | 20 |
age | int | 0 |
adreess | varchar | 50 |
我们查询phone字段为具体数值的查询,可以为:
select * from t_test where phone =13555455506
可以正常得到我们想要的结果,但是由于phone为varchar字符类型,而不是长整型,所以我们查看下这个sql的执行计划:
explain select * from t_test where phone =13555455506
并且可以得到以下计划:
id | select_type | table | partitions | type | possible_keys | key | key_length | ref | rows | filtered | Extra |
1 | SIMPLE | t_test | | ALL | index_phone | | | | 1 | 100 | Using where |
我们可以通过上述列表看到possible_keys为执行时预计可能用到的索引为phone上的索引,key为实际用到的索引为空,则表示实际查询不会用到索引,则是因为MySQL会将我们传入的参数隐式转换为数据表中存储的类型,索引时根据Btree的有序性进行遍历的,但是转换之后的参数破环了有序性的规则。
所以我们要将传入参数加上引号,以表示此参数为字符串类型,如下:
select * from t_test where phone ='13555455506'
二.表达式计算
还是使用上面的表,我们在age字段上加入索引,现在我们有一个查询,要求查询年龄age在两年前为18的数据,则查询语句如下:
select * from t_test where age -2=18
可以正常得到我们想要的结果,但是由于我们在age查询的时候给他赋予了表达式,所以我们查看下这个sql的执行计划:
explain select * from t_test where age -2=18
并且可以得到以下计划:
id | select_type | table | partitions | type | possible_keys | key | key_length | ref | rows | filtered | Extra |
1 | SIMPLE | t_test | | ALL | | | | | 1 | 100 | Using where |
我们可以清楚看到,索引并没有使用,那么我们应该如何修改以达到要求呢,我们只需要把计算挪到等号右侧即可:
select * from t_test where age =18+2
原因与第一个类似。数据库在计算时无法保证与索引树一致,只好不用索引。
三.使用函数
现在我们有这样一个查询,查询出手机号码前三位为158的数据,则查询语句如下:
select * from t_test where LEFT(phone,3)='158'
可以正常得到我们想要的结果,但是由于我们使用了函数,所以我们查看下这个sql的执行计划,语句省略,直接看结果:
id | select_type | table | partitions | type | possible_keys | key | key_length | ref | rows | filtered | Extra |
1 | SIMPLE | t_test | | ALL | | | | | 1 | 100 | Using where |
我们可以修改为如下语句:
select * from t_test where phone like '158%'
原因同上面两个类似,这正是用到了我们msyql的索引最左原则进行匹配。
四.左或者左右模糊匹配
现在我们有这样一个查询,查询出地址包含天安门的数据,则查询语句如下:
select * from t_test where adreess like '%天安门%'
可以正常得到我们想要的结果,但是由于我们使用了左右模糊匹配,则可以查看sql的执行计划如下,查看结果:
id | select_type | table | partitions | type | possible_keys | key | key_length | ref | rows | filtered | Extra |
1 | SIMPLE | t_test | | ALL | | | | | 1 | 100 | Using where |
这里面也是由于不符合最左前缀匹配原则。如果我们只查询主键id与该索引字段,仍可使用索引,查询如下:
select id,adreess from t_test where adreess like '%天安门%'
由于不符合最左前缀,即使使用索引树,查询只能跟随Btree数依次遍历。
五.联合索引
联合索引我们要依据最左前缀原则,即最左字段,最左数据
如果我们删除age与phone上的单列索引,新增(age,phone)联合索引,则有以下规律
select * from t_test where age =20 //使用了该联合索引
select * from t_test where phone like '131%' //没有使用该联合索引
select * from t_test where age =20 and phone like '131%'//使用了该联合索引