你的like语句为啥没索引?

本文旨在用最通俗的语言讲述最枯燥的基本知识sql

这个话题比较有意思。
昨天中午吃完饭间忽然有个同事蹦出了一句:“like有索引吗?”,我顺口就说没有,另外一个同事反驳说有啊,还有些同事说看状况的有,这下有点懵逼了,都不知道那种说法是正确的,因而决定花了个半小时来研究验证这个问题,终于获得答案。编程

怎么验证的呢?缓存

坊间有传言:MySQL性能优化有个神器,叫作explain,它能够对select语句进行分析而且输出详细的select执行过程的详细信息,让开发者从这些信息中得到优化的思路。性能优化

下面来说讲这个MySQL提供的explain命令:app

语法:explain SQL语句
例如:函数

1explain select * from user where id=1
复制代码

执行完毕以后,它的输出有如下字段:性能

  • id
  • select_type
  • table
  • partitions
  • type
  • possible_keys
  • key
  • key_len
  • ref
  • rows
  • Extra

要想知道explain命名怎么使用,就必须把这些字段搞清楚优化

1. id

SELECT查询的标识符, 每一个SELECT语句都会自动分配一个惟一的标识符ui

2. select_type

每一个select查询字句的类型,具体类型以及对应做用以下表:spa

类型名 解释
SIMPLE 简单SELECT,不使用UNION或子查询等
PRIMARY 查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY
UNION UNION中的第二个或后面的SELECT语句
DEPENDENT UNION UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT UNION的结果
SUBQUERY 子查询中的第一个SELECT
DEPENDENT SUBQUERY 子查询中的第一个SELECT,取决于外面的查询
DERIVED 派生表的SELECT, FROM子句的子查询
UNCACHEABLE SUBQUERY 一个子查询的结果不能被缓存,必须从新评估外连接的第一行

3. table

显示这一行的数据是查哪张表的,不过有时短路显示的不是真实的表名。

4. partitions

匹配的分区(这个目前用处不大)

5. type

访问类型,表示MySQL在表中找到所需行的方式,对应的值和解释以下:

类型名 优级别 解释
system 1 表仅有一行
const 2 表最多有一个匹配行,在查询开始时即被读取
eq_ref 3 使用primary key或者unique key做为多表链接的条件,仅从该表中读取一行
ref 4 做为查询条件的索引在每一个表匹配索引值的行从表中读取出来
fulltext 5 全文索引检索
ref_or_null 6 和ref一致,但增长了NULL值查询支持
index_merge 7 表示使用了索引合并优化方法
unique_subquery 8 使用了替换了in子查询
index_subquery 9 使用了替换了in子查询,但只适用于子查询中的非惟一索引
range 10 只检索给定范围的行,使用一个索引来选择行
index 11 全表扫描,但扫描表的方式是按索引的次序进行
ALL 12 全表扫描的方式找到匹配的行

type做为访问类型,其值表明着当前查询所用的类型,是体现性能的一个重要指标,从表中能够看到,从上到下,扫描表的方式愈来愈宽,性能也就愈来愈差,所以,对于一个查询,最好能保持在range级别以上。

6. possible_keys

主动指出查询能用哪一个索引在表中找到记录
也就是会列出在查询中的字段中有索引的字段,但不必定被查询所用。

7. key

显示再查询中实际使用的索引/键,若是没有索引,则显示NULL。
但若是想强制查询中使用或忽视possible_keys列中的索引,则能够在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

8. key_len

表示索引中使用的字节数。

9. ref

表示哪些列或常量被用于查找索引列上的值。

10. rows

显示当前查询估算到的查找到匹配记录所需的记录行数。

11. Extra

显示当前查询所用的解决方式,它有如下几种状况:

类型名 解释
Using where 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,
Using temporary 表示MySQL须要使用临时表来存储结果集,常见于排序和分组查询
Using filesort MySQL中没法利用索引完成的排序操做称为“文件排序”
Using join buffer 改值强调了在获取链接条件时没有使用索引,而且须要链接缓冲区来存储中间结果。若是出现了这个值,那应该注意,根据查询的具体状况可能须要添加索引来改进能。
Impossible where 这个值强调了where语句会致使没有符合条件的行。
Select tables optimized away 这个值意味着仅经过使用索引,优化器可能仅从聚合函数结果中返回一行

讲完了语法,咱们来实际操做一波,首先建立个表:

1-- 建立表
2CREATE TABLE test(
3id INT(11NOT NULL AUTO_INCREMENT,
4uname VARCHAR(255),
5PRIMARY KEY(id
6);
复制代码

而后给uname字段加上索引:

1-- 添加索引
2ALTER TABLE test ADD INDEX uname_index (uname);
复制代码

查看一下索引是否添加成功:

1-- 查看是否有索引
2SHOW INDEX FROM test;
复制代码

输出结果为:


能够看出索引已经建立成功,接下来添加一些数据:

1-- 添加一些数据
2INSERT INTO test VALUES(1,'jay');
3INSERT INTO test VALUES(2,'ja');
4INSERT INTO test VALUES(3,'bril');
5INSERT INTO test VALUES(4,'aybar');
复制代码

一切准备就绪,下面用explain这个命令来探究一些like语句是否有索引,
like有四种状况,分别为没有%、 %% 、左%、右%、

1. like 字段名

1EXPLAIN SELECT * FROM test WHERE uname LIKE 'j'
复制代码

输出为:

能够看出:
type的值为:range,key的值为uname_index,也就是说这种状况下,使用了索引。

2. like %字段名%

1EXPLAIN SELECT * FROM test WHERE uname LIKE '%j%'
复制代码

输出为:

能够看出:
type的值为ALL也就是全表扫描,并且key的值为NULL,也就是说没用到任何索引。

3. like %字段名

1EXPLAIN SELECT * FROM test WHERE uname LIKE '%j'
复制代码

输出为:


能够看出:
type的值为ALL,key的值为NULL,一样没用到索引。

4. like 字段名%

1EXPLAIN SELECT * FROM test WHERE uname LIKE 'j%'
复制代码

输出为:


能够看出:
type的值为:range,key的值为uname_index,也就是说这种状况下,使用了索引。

总结

由上面的试验能够总结出like是否使用索引的规律:
like语句要使索引生效,like后不能以%开始,也就是说 (like %字段名%) 、(like %字段名)这类语句会使索引失效,而(like 字段名)、(like 字段名%)这类语句索引是能够正常使用。

其它

为了查证like索引的问题,研究了MySQL神奇explain,但explain不只仅只能检查索引使用状况,还能够提供不少其它的性能优化方面的帮助,至于具体的使用,其实跟上面讲的同样,把explain结果列出来,而后顺藤摸瓜查阅相关的字段就能够获得相应的内容。


以为本文对你有帮助?请分享给更多人
关注「编程无界」,提高装逼技能

相关文章
相关标签/搜索