在Mysql中,索引是在存储引擎层而不是服务器层面实现的。所以并没有统一的标准:不同的存储引擎的索引的工作方式并不一样,也不是所有的存储引擎支持所有类型的索引。
B-Tree索引
Mysql支持该索引,但是实际上很多存储引擎使用的是B+Tree,即每个叶子节点都包含指向一个下一个叶子节点的指针,从而方便叶子节点的范围遍历。
InnoDB则使用的是B+Tree,B-Tree通常意味着所有的值都是按顺序存储,并且每一个叶子页到根的距离相同。
B-Tree索引能够加快访问数据的速度,因为不需要全表扫描,而是通过索引的根节点开始搜索,根节点的槽中存放了叶子节点的指针,存储引擎根据指针查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点。
叶子节点比较奇怪,它们的指针指向的是被索引的数据,而不是其他的节点页。
假设有如下数据表:
CREATE TABLE People(
last_name varchar(50) not null,
first_name vachar(50) not null,
dob date not null,
gender varchar(50) not null,
key(last_name,first_name,dob)
);
看上图,索引对多个值进行排序的依据是CREATE TABLE语义中定义索引的顺序。看最后两个条目,姓名都是一样的,按照日期排序。
1、全值匹配,按照索引的所有列进行匹配。
2、匹配最左前缀
3、只访问索引的查询,B-Tree通常可以支持“只访问索引的查询",即查询只需要访问索引,无需访问数据行。后面单独讨论覆盖索引的优化
哈希索引
哈希索引基于哈希表实现。只有精准的匹配索引所有列的查询才有效。
1、哈希索引只包含哈希值和行指针,而不是存储字段值,所以不能使用索引中的值避免读取行。
2、哈希索引数据不是按顺序存储的,所以无法排序
3、哈希索引也不支持部分索引列匹配查找,因为使用的是索引列的全部内容计算hash值的。
空间数据索引(R-Tree)
MyISAM支持空间索引,可以用作地理数据存储。和B-Tree不同的是,索引无需前缀查询。空间索引可以通过维度来进行查询。
全文索引
特殊的索引,可以查找文本中的关键词,全文索引做的更像是搜索引擎的事情,而不是简单的where查询
索引的优点
1、索引大大的减少了服务器需要扫描的数据量
2、索引可以帮助服务器避免排序和临时表
3、索引可以将随机I/O变为顺序I/O
那么怎么使用索引是最关键的地方
聚簇索引
聚簇索引并不是一种单独的索引类型,而是一种数据存储的方式,但InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。
当表有聚簇索引时,它的数据行实际上存放在索引的叶子页中,术语"聚簇"表示数据行和相邻的键值紧凑的存储在一起。因为无法同时把数据行放两个不同的地方,所以一个表只能有一个聚簇索引,不过覆盖索引可以模拟多个聚簇索引
聚簇索引的叶子页包含了行的全部数据,但是节点只包含了索引列。如下
如果没有主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键作为聚簇索引。
聚簇索引优点:
1、访问速度快
2、使用覆盖索引扫描的查询可以使用页节点的主键值
3、减少IO次数
聚簇索引缺点:
1、聚簇数据最大限度提高了IO密集型应用的性能,但是数据全部放在内存中,访问顺序不那么重要了,优势也就不复存在了
2、插入速度严重依赖插入顺序
3、可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致的数据存储连续
InnoDB的数据分布。因为支持聚簇索引,所以使用的方式非常不同,如下图:
在InnoDB中,该图显示了整个表,因为聚簇索引就是表。
聚簇索引的每一个叶子节点都包含了主键值、事务ID、用于事务和MVCC(多版本控制)的回滚指针以及所有剩余列。
与MyIsam不同的是,InnoDB的二级索引和聚簇索引很不相同。InnoDB二级索引的叶子节点中存储的不是行指针,而是主键值,并以此作为指向行的指针。
覆盖索引
通常都是通过where查询语句。那么如果一个索引所需要查询的字段的值,就称作覆盖索引。
比如:
//假设name是索引列
select user_id where name = "AAA" ;
发现查询速度还是很慢,这时候将user_id加入索引即是覆盖索引,直接返回。 idx(name,user_id)。