1、范围查找索引失效的情况
当 Mysql 发现通过索引扫描的行记录数超过全表的 10%-30% 时,优化器可能会放弃走索引,自动变成全表扫描。某些场景下即便强制 SQL 语句走索引,也同样会失效。
类似的问题,在进行范围查询(比如 >、< 、>=、<=、in 等条件)时往往会出现上述情况,而上面提到的临界值根据场景不同也会有所不同。
2、Limit 分页
如果对于有 where 条件,又想走索引用 limit 的,必须设计一个索引,将 where 放第一位,limit 用到的主键放第 2 位,而且只能 select 主键。这样才能完美解决 MySQL 的分页问题了。
到了 100 万的数据,160 万数据,15G 表,190M 索引,就算走索引,limit 都得差不多 0.5 秒。所以分页最好别让别人看到 10万 条以后的数据, 要不然就算用索引也会很慢。
3、对索引字段做函数操作
对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能。
比如:
select count(*) from t where month(t_create_time)=7;
如果我们因为 t_create_time 字段上有索引,于是就很放心地执行了这条语句,但却发现执行了特别久,才返回了结果。我们可以这么理解,在MySQL 中,如果对字段做了函数计算,由于加了 month() 函数操作,MySQL 无法再使用索引快速定位功能,而只能使用全索引扫描,所以就会很慢。
可以优化如下:
select count(*) from t where (t_create_time>= '2021-7-1' and t_create_time<'2021-8-1') or (t_create_time>= '2020-7-1' and t_create_time<'2020-8-1') or (t_create_time>= '2019-7-1' and t_create_time<'2019-8-1');
就可以使用 t_create_time 索引快速定位功能。
4、隐式类型转换
先看下这个SQL:
select * from t where tradeid=110717;
交易编号 tradeid 这个字段上有索引,但是 explain 的结果却显示,这条语句需要走全表扫描。
其实我们的 tradeid 的字段类型是varchar(32),而输入的参数却是整型,所以需要做类型转换。
相当于把 varchar 类型做了函数转换成了 int 类型,基于上面第 3 种情况,所以就走了全表扫描。