MySQL 索引失效原因:
+
、-
、*
、/
),索引失效NOT
、!=
、<>
、NOT IN
、NOT LIKE
)时,可能会导致索引失效is null
, is not null
,可能导致索引失效userId
有索引、age
没有索引:不走索引
select * from user where userId = '123' or age = 18
【解释】:即使它走了 userId
索引,但走到 age
查询条件时,它还得经历全表扫描,也就是需要三步:索引扫描 + 全表扫描 + 合并。如果一开始就进行全表扫描就完事了。MYSQL 优化器出于效率、成本考虑,遇见 or
条件,使索引失效,这样也合情合理
【注意】:如果 or 条件的列都加了索引,索引可能会走也可能不走
如果 or 条件不走索引,可考虑拆开两条 SQL 进行优化
【优化】:改成 UNION
或者 UNION ALL
,分成多个 sql,走各自的索引
UNION
和 UNION ALL
的区别:MySQL 8.0 的官方文档规则描述了比较操作如何进行转换:
num_int
字段是 int
类型,num_str
字段是 varchar
类型,且都建有各自的索引
# int 类型
SELECT * FROM `test1` WHERE num_int = 10000;
SELECT * FROM `test1` WHERE num_int = '10000';
# varchar 类型
SELECT * FROM `test1` WHERE num_str = 10000;
SELECT * FROM `test1` WHERE num_str = '10000';
在大数据量情况下,第一、二、四条 sql 执行时间相差无几;而第三条没有用上索引,所以执行时间较长
根据文档描述,我们知道第二、三条 sql 都发生了 隐式转换,”=“ 左右两边都会转换为浮点数再进行比较
第二条 sql:
SELECT * FROM `test1` WHERE num_int = '10000';
左边是 int 类型,只有值为 10000
的浮点数是 10000
;右边是 varchar 类型的 '10000'
,那么转化为浮点数是 10000
。两边的转换结果都是唯一确定的,所以不影响使用索引
第三条 sql:
SELECT * FROM `test1` WHERE num_str = 10000;
左边是 varchar 类型,不仅仅值为 '10000'
的浮点数是 10000
,其他字符串也可以转换为 10000,比如:'10000a'
、'010000'
、'10000'
等等都能转为浮点数 10000;右边是 int 类型的,转化为浮点数 10000
。由于 varchar 转化为浮点数并不唯一,所以,是无法使用索引的
所以,我们在写 SQL 时一定要养成良好的习惯,查询的字段是什么类型,等号右边的条件就写成对应的类型。特别当查询的字段是字符串时,等号右边的条件一定要用引号引起来标明这是一个字符串,否则会造成索引失效触发全表扫描
select * from user where userId like ‘%123’
%
在左边的时候:匹配字符串尾部的数据,由于尾部的数据是没有顺序的,所以不能按照索引的顺序查询,就用不到索引,就会使索引失效%
在右边的时候:由于B+树的索引顺序,是按照首字母的大小进行排序,%号在右的匹配又是匹配首字母,所以可以在B+树上进行有序的查找,可以用到索引%
时:这个是查询任意位置的字母满足条件即可,只有首字母是进行索引排序的,其他位置都是相对无序的,索引此时也是用不到索引的问题:
既要 通配符在左边,且索引不失效
建立:覆盖索引
如:建立复合索引:(name, age)
select name
from test
where name like '%5'
字段 create_time
建立索引
# 索引失效
select count(*) from tradelog where month(create_time) = 7;
# 索引生效
select count(*) from tradelog where create_time = '2018-7-1’
create_time
索引示意图(方框上面的数字就是 month()
函数对应的值):
如果你的 sql 语句条件用的是 where create_time = '2018-7-1’
的话,引擎就会按照上面绿色箭头的路线,快速定位到 create_time='2018-7-1’
需要的结果
实际上,B+ 树提供的这个快速定位能力,来源于同一层兄弟节点的有序性
但是,如果计算 month()
函数的话,你会看到传入 7 的时候,在树的第一层就不知道该怎么办了
即:对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能
+
、-
、*
、/
),索引失效同 1.4
NOT
、!=
、<>
、NOT IN
、NOT LIKE
)时,可能会导致索引失效这个也是跟 MYSQL 优化器有关,如果优化器觉得即使走了索引,还是需要扫描很多很多行的话,它觉得不划算,不如直接不走索引
is null
, is not null
,可能导致索引失效is null
或 is not null
,而不能采用 in、<、<>、!=、not in 这些操作符号MySQL 建立联合索引时,会遵循最左前缀匹配的原则,即最左优先。在联合索引中,查询条件满足最左匹配原则时,索引才正常生效
复合索引 (name, age, pos)
# 情况一:索引生效
select name
from test
where name = 'zzc' and age = 22
# 情况二:索引失效
select name
from test
where age = 22 and pos = '11'
# 情况三:name 索引不失效,pos 索引失效
select name
from test
where name = 'zzc' and pos = '11'