经历了前面两篇的介绍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关键字,若是值是’%XXX’或者’%XXX%’,则没法使用索引。
若是值是’XXX%’,能够正常使用索引。这是由于通配符’%'位于前面,会致使查询优化器不得不使用全表查询,致使索引失效。
好比下面的SQL语句:
select * from t4 where id like '%1';
若是业务中必需要用到模糊查询的话,咱们能够试着引入全文搜索引擎ElasticSearch。
篇幅缘由,我就不一一演示了,直接说结论,大家也能够去试试。
查询数据库表,WHERE条件不包含索引列,可是GROUP BY子句的条件中包含索引列。这个时候即便explain会显示它是走group by字句的索引,可是扫描的rows也是接近于全表扫描。
你能够本身对比一下,WHERE字句中的条件有索引和无索引的SQL性能将会差距很是大,在全表扫描的状况下SQL的性能惨不忍睹。
和上面的GROUP BY子句相似,在MySQL查询优化器的代价估算模型中, ORDER BY和GROUP BY的代价,相对来讲很是高,若是有索引就会尽量的使用它。
根据上面的第6条和第7条,只要给SQL语句中的WHERE子句和ORDER BY/GROUP BY子句加上一个联合索引就能够解决全表扫描的问题。
联合索引中索引失效的状况:
但愿大家读完这篇文章, 可让大家在MySQL的这条路上少走弯路~~~