完整的访问方法包括 system、const、eq_ref、ref、fulltext、ref_or_null、index_merge、unique_subquery、index_subquery、range、index、ALL。为了方便大家阅读,我先单独整理一个表格来说明各个级别的具体含义,然后再分别具体说明级别信息。
类型 | 描述 | 备注 |
---|---|---|
system | 如果表里面只有一条数据,而且表使用的存储引擎(如 MyISAM)的统计信息是准确的。 | 条件太苛刻,几乎见不到 |
const | 使用主键或唯一二级索引与常数进行等值匹配时 | 效率高,常见 |
eq_ref | 连接查询是,如果被驱动表是通过主键或者不允许为 null 的唯一二级索引列进行等值匹配的方法访问的 | 常见 |
ref | 通过普通的二级索引与常数进行等值匹配时 | 常见 |
fulltext | 全文索引 | 几乎用不到 |
ref_or_null | 对二级索引进行等值匹配且该索引的值也可以为 null 的时候 | 常见 |
index_merge | 两个以上的索引合并 | 不常见 |
unique_subquery | 如果子查询可以转换为 EXISTS 子查询,而且转换之后可以使用主键或者不允许为 null 的唯一二级索引进行等值匹配 | |
index_subquery | 如果子查询可以转换为 EXISTS 子查询,而且转换之后可以使用普通二级索引进行等值匹配 | |
range | 使用索引进行范围查询 | 常见 |
index | 使用索引覆盖,扫描前部索引记录的时候 | 常见,但是不推荐 |
ALL | 全表扫描 | 常见,但是不推荐 |
为了方便理解,每个我们都举一个具体的例子,当然如果你的时间有限,可以不看下面的内容,只需要记住上面的这个表格就可以了:
-
system 这个基本上见不到的,他要求表对应的存储引擎的统计信息是准确的,而我们通常是使用 InnoDB 存储引擎,而这个存储引擎的统计信息是不准确的。so,forget it;
-
const 这个就非常常见了,当我们使用主键索引或者唯一二级索引搜索非空的等值查询的时候,就是走的这个类型
比如说 SELECT * FROM info_information_unit WHERE id = 1
-
rq_ref 单独拿出这个类型来,可能你会觉得有点眼生,实时上,我们常常在用。因为我们表结构设计上通常会使用一个表的主键和另外一个表关联起来,这个时候被驱动表的类型就是 rq_ref
比如说:SELECT * FROM website_column wco LEFT JOIN website_label wl ON wco.id = wl.id WHERE wl.id = 123;
-
ref 这个其实我们也非常非常的常见,如果我们是使用我们添加的普通二级索引进行查询的话,他的级别就是 ref,例子太多了,我敢保证你的单标查询的 SQL 起码百分之五十以上这样的。
比如说:SELECT * FROM info_information_unit WHERE code = 'xxx';
-
fulltext 全文索引,其实目前 MySQL 支持了全文索引,而且现在也支持了中文的分词器。但是,实际上绝大多数场景下,针对分词查询这种倒排索引的应用场景,我们通常会使用更加成熟的 Elasticsearch。这里不展开讲述了。
-
ref_or_null 在我的理解里面,这种其实是一种特殊的 ref,和 ref 的区别在于他接受该索引列的值可是null 的情况。
比如说:SELECT * FROM info_information_unit WHERE code = 'a' or code IS NULL;
-
index_merge 我必须得说,学习这个类型之前,在我的认知里面,我们的查询 SQL 中无论可以匹配上多少个索引,最终都会通过查询优化器计算出成本最小的一个索引,然后使用这个索引对数据进行查询。而这种是在某种常见下可以使用 Intersection、union、sort-union 这 3 种索引合并的方式来执行查询的。
比如说:SELECT * FROM s1 WHERE key1 = 'a' AND key3 = 'a';
-
unique_subquery 和 index_subquery 这两个只是最终是否能够使用主键或者不允许存储 null 的唯一二级索引进行匹配这一点上有差异,其他都是一样的。所以我们把他们放在一起说。
他们都是针对一些包含 IN 子查询的查询语句,如果查询优化器决定将 IN 子查询转换为 EXISTS 子查询的话就会出现上面这种。
这里特殊说明一下,很多小伙伴对什么情况下查询优化器才会把 IN 子查询转换 EXISTS 子查询表示好奇,我后面会梳理查询优化器对 IN 语句的特殊关照的相关材料,等我。
-
range 这个大家看起来应该也很眼熟吧,如果我们使用范围查询的时候,经常看到他。
-
index 这个偶尔会看到,但是也不是很常见,这种情况下其实相当于是对于二级索引这棵树进行了全表扫描,他会扫描全部的索引记录,比如说我们查询联合索引的非第一个字段的时候,而且不需要回表的时候
-
ALL 这个最熟悉的全表扫描了,老实讲,我希望你的查询 SQL 的执行计划中看不到他。