MySQL索引(三)索引不生效的状况

背景

经历了前面两篇的介绍MySQL索引,相信你们也能够很清晰的认识到索引。这一节想分享一下在MySQL中给字段加了索引,可是查询的时候却不生效索引的状况,让更多的开发者能够少踩坑,接下来直接进入正文~~~web

为何索引不生效

在上一篇MySQL(二)如何设计索引咱们有提到过,MySQL使用的是基于成本的优化器,可是因为查询优化技术是关系型数据库实现中的难点,所以总会有一些索引不生效的状况。sql

接下来咱们先创建一张表,而且插入模拟数据,来分析什么状况索引不生效。数据库

CREATE TABLE `t4` (
  `id` int NOT NULL AUTO_INCREMENT,
  `account` varchar(50) DEFAULT NULL,
  `client_type` tinyint DEFAULT NULL,
  `security_code` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_client_type` (`client_type`),
  KEY `idx_account` (`account`),
  KEY `idx_security_code` (`security_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

一、在索引字段上运算

查询数据库表的时候,已经建立了索引,WHERE条件中也包含了索引列,可是列对象上有函数或者运算符,这样会致使索引失效。svg

好比下面这条SQL语句:函数

select * from t4 where id-1 = 1;

在这里插入图片描述

从上面实验的执行计划能够得出,在索引列上使用函数或者运算符,会致使索引没法生效。性能

二、多个索引字段进行运算

查询数据库表时,已经建立了索引,WHERE条件中也包含了索引列,可是列对象进行了运算操做。优化

好比下面这条SQL语句:搜索引擎

select * from t4 where id + client_type = 1;

在这里插入图片描述

从以上实验来看,即便两个列上都有索引字段,MySQL仍然没法在表达式中使用这些索引。spa

三、隐性转换

若是索引列是INT类型,隐性转换可使用到索引。可是若是索引列是字符型,隐性转换没法使用索引。设计

好比下面这条SQL语句:

# 不能使用索引,由于security_code字段是字符,它要变成INT型才能和688688比较,因此索引失效
select * from t4 where security_code = 688688;

# 可使用索引,由于查询优化器是把'1'变成1,而后索引列没有变化,可使用索引。
select * from t4 where id = '1';

在这里插入图片描述

在当前版本中,MySQL查询优化器已经能够转换字符型数字了,从而使用索引。可是反过来,索引失效。

四、Like

LIKE关键字,若是值是’%XXX’或者’%XXX%’,则没法使用索引。

若是值是’XXX%’,能够正常使用索引。这是由于通配符’%'位于前面,会致使查询优化器不得不使用全表查询,致使索引失效。

好比下面的SQL语句:

select * from t4 where id like '%1';

在这里插入图片描述

若是业务中必需要用到模糊查询的话,咱们能够试着引入全文搜索引擎ElasticSearch。

五、OR操做符

篇幅缘由,我就不一一演示了,直接说结论,大家也能够去试试。

  1. OR条件的两边都是同一个索引列的状况下,若是WHERE条件是主键,则可使用索引
  2. OR条件的两边都是同一个索引列的状况下,若是WHERE条件不是主键,则是否使用索引取决于MySQL查询优化器的代价估算。
  3. OR条件的两边是不一样的索引列,是否使用索引取决于MySQL查询优化器的代价估算。若是能使用索引,MySQL会使用索引,若是代价过高,仍然会走全表索引
  4. 若是多个OR条件中有其中一个条件没有索引,则必须进行全表索引

六、GROUP BY子句

查询数据库表,WHERE条件不包含索引列,可是GROUP BY子句的条件中包含索引列。这个时候即便explain会显示它是走group by字句的索引,可是扫描的rows也是接近于全表扫描。

你能够本身对比一下,WHERE字句中的条件有索引和无索引的SQL性能将会差距很是大,在全表扫描的状况下SQL的性能惨不忍睹。

七、ORDER BY子句

和上面的GROUP BY子句相似,在MySQL查询优化器的代价估算模型中, ORDER BY和GROUP BY的代价,相对来讲很是高,若是有索引就会尽量的使用它。

八、联合索引

根据上面的第6条和第7条,只要给SQL语句中的WHERE子句和ORDER BY/GROUP BY子句加上一个联合索引就能够解决全表扫描的问题。

联合索引中索引失效的状况:

  • 没有使用索引前缀,就是没有遵循联合索引的最左匹配原则
  • 使用了联合索引的所有列,可是索引键不是AND操做,可能使用了OR操做符

总结

  • 这一节讨论了MySQL中没法使用索引的一些场景,可能会有遗漏,有错误的地方能够评论区提出来。
  • 对于WHERE子句来讲,建议不要把运算操做放到SQL语句中,能在代码里面去运算尽可能在代码里面运算,能够避免索引失效
  • 若是模糊查询比较多,能够引入ES来帮助你进行模糊查询
  • ORDER BY和GROUP BY这两个子句,须要防范的问题是没有给WHERE条件设计索引,你在查看执行计划时也会比较迷惑,因此必定要注意

但愿大家读完这篇文章, 可让大家在MySQL的这条路上少走弯路~~~