索引对于良好的性能非常关键,尤其是在数据量越来越大的时候。恰当的索引对性能的帮助是非常巨大的,不恰当的索引不禁不能对性提升有帮助,当数据量达到一定级别的时候还可能造成性能的下降。所以了解索引对
Mysql
性能优化有着至关重要的作用。
Mysql 索引基本类型有 B-Tree
,哈希索引
, 全文索引
, 空间数据索引 (R-Tree)
。其中B-Tree
、 哈希
、 全文索引
是我们经常用到的。
B-Tree 索引
B-Tree
索引是我们口中经常说的索引类型(有些存储引擎中使用的是 B +Tree。如 InnoDB)。每个引擎对于 BTREE 索引使用方式是不一样的。
如
-
MyISAM
引擎使用的是前置压缩技术,这样索引会变的很小。而InnoDB
则是按照原有的数据格式来存储的。 -
MyISAM
索引是通过数据的物理位置来找到被索引的行,而InnoDB
则是根据被索引的行的主键来找到被索引行的。
B-Tree
索引的所有值都是按顺序存储的,并且每个叶子节点到根节点的距离是相同的。下面给出一个简单的示意图
假设有下表:
CREATE TABLE student(first_name varchar(20) not null,
last_name varchar(20) not null,
age tinyint(3) not null,
created_at timestamp not null,
key(first_name ,last_name)
);
可以使用到 B-Tree
索引的查询
- 全值匹配 全值匹配指对索引中的所有列进行匹配。如查询姓名是
zhang san
的人select * from student where first_name='zhang' and last_name='san';
这里使用了索引的第一列与第二列 - 匹配最左前缀,如查询姓为
张
的人select * from student where first_name='zhang' ;
这里使用了索引的第一列 - 匹配列前缀,也可以值匹配某一列的开头部分, 如
select * from student where first_name='zha' ;
这里使用了索引的第一列 - 匹配范围值, 如
select * from student where first_name>'bao' and first_name<'zhang';
这样也会使用到索引的第一列 - 只访问索引的查询,如果查询条件是
select first_name,last_name from student where first_name='zhang' ;
那么查询就只会访问索引,而不会再去根据主键回表查询数据。
这里需要注意的是;
B-Tree
索引需要根据最左前缀查询,如果不是按照索引的最左列开始查询,那么是不会使用到索引的。例如:select * from student where last_name='san';
select * from student where first_name like '%ha%';
这样的sql
是没办法命中索引的。对于第二条sql
如果需要使用索引,那么应该改为select * from student where first_name like 'ha%';
哈希索引
哈希索引是基于哈希表实现的,只有精确匹配索引所有列的查询才会使用到索引,只有 Memory
引擎才支持哈希索引。
假设有下表:
CREATE TABLE student(first_name varchar(20) not null,
last_name varchar(20) not null,
age tinyint(3) not null,
created_at timestamp not null,
key using hash(first_name)
) engine=memory;
如果我们要执行 select last_name from student where first_name='zhang';
,Mysql
会先计算 zhang
的哈希值,然后用该值寻找对应的记录指针,最后再去比较 first_name
是否等于 zhang
。
因为哈希索引只存储对于的哈希值和行指针,所以哈希索引的结构很紧凑,查询速度非常快。但是也有一些缺点。
- 因为哈希索引只有哈希值与指针,所以每次查询必须回表去读取数据行。
- 因为哈希索引不是按照索引值顺序存储的,所以哈希索引也不能用于排序。
- 哈希索引不支持部分索引列查询,比如 将
student
表是索引 改为hash(first_name,last_name)
,那么查询必须用到first_name,last_name
才会使用到索引。 - 哈希索引只支持等值比较,所以
<,>
等范围查询是不会使用到索引的。 - 哈希索引也会存在哈希冲突,当出现冲突的时候,查询效率就很降低很多。