索引

102 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

索引

在MySQL官方的文档中,索引是帮助MySQL高效获取数据的数据结构。

就像我们平常所看的书的目录,如果没有目录,我们就只能一页一页翻找我们想要的内容。而索引同样,如果不存在索引,系统就只能按照字典序一条记录一条记录的查询我们想要的目标。

当然,索引也并不是没有缺点,它毕竟是一种数据结构,就如同我们熟悉的哈希表,红黑树等数据结构一样,高效的查询带来的必定是插入、更新、删除速度的降低。

磁盘

数据库所存储的数据都是掉电不清除的,这是一个很明显的特点,这说明了数据库是将数据存储在磁盘之中的。但是,作为计算机中不可或缺的机械设备,磁盘相较于其它电子元件,其IO效率明显有些不足——这也是为何我们需要内存的原因之一。而数据库是如何提高数据在磁盘上的存取效率的?

这就需要我们先简单认识一下磁盘了。

扇区

深入了解磁盘是如何存储数据的,其掉电保存的原理又是什么……这显然不是我这短短的一篇文章可以写完的,也偏离了我们这篇文章的主题。

这里我们只需要了解一个概念——扇区。

所谓扇区,是磁盘的磁道上被划分出来的一个个小段,每个磁道上的小段的大小可能不同,但至少就目前而言,每一段的存储容量都是相同的,即,512字节(当然现在也有更大容量,更高效的扇区,大小为4096字节)。

数据库文件,本质上便是保存在这些扇区之中的,但是,以我们现在的了解就可以看出,数据库文件很大,并且很多,单一的扇区肯定是放不下的,于是就需要占据多个扇区。而我们在寻找数据的时候,只要能够定位任意一个扇区,就能够查找到所有的扇区,也即找到我们所有的数据。

MySQL的page

虽然一个扇区的大小是512字节,但是貌似没有谁按照一个扇区一个扇区的大小来读取磁盘中的内容,操作系统往往会按照它自定义的一个单位——块来读取,而一块的大小通常为4KB。至于我们此处所讲的MySQL,为了提高基本的IO效率,往往会以16KB为基本数据单元,而MySQL中将这个基本数据单元称为page。

关于更加详细的MySQL的IO,相关资料多是使用InnoDB存储引擎进行讲解,其中往往会涉及到两种鼎鼎大名的数据结构——B树以及B+树。这由于我个人实在太菜,就不班门弄斧,误人子弟了。

聚簇索引与非聚簇索引

简单解决一下上一篇文章中关于主键与唯一键的遗留问题,聚簇索引(聚集索引)与非聚簇索引(非聚集索引)。

聚簇索引与非聚簇索引本质上是B+树索引按照存储方式的不同进行的分类。

要说B+树就要先提到B树。而B树,我们还是要从平衡二叉树来讲起。

平衡二叉树是一种特殊的二叉查找树,它可以通过算法使得所有叶子节点的高度相差不会过大,从而保证了整棵树的高度尽可能小,提高了查找的效率。但是,如果用在磁盘中数据的查找上,平衡二叉树的效率就有点促襟见肘了,尤其是在数据库中文件大且多的情况下,二叉树的节点会非常多,高度也会变得极高。此时就需要一种单个节点可以存储多个键值和数据的平衡树——B树。

B树相对于平衡二叉树,其每个节点存储了更多的键值以及数据,并且每个节点的子节点个数也不再局限于两个,而是可以更多,一般会将子节点个数称之为阶。由于这种种特性,使得B树的高度相对于平衡二叉树降低了许多,也极大的提高了读取效率。

B+树是另一种平衡的多叉树,它与B树非常相像,但又有很大不同。首先,B树的节点又有数据又有键值,而B+树的非叶节点只有键值,省去了数据也使得它的非叶节点可以存储更多的键值,使得树更加矮。B+树的叶子节点中存有数据与键值,但也不仅如此,B+树的相邻叶子节点之间是相连的,这样在一定程度上方便了范围查找。

在存在主键的情况下,以主键作为B+树索引的键值而构建的B+树索引,被称为聚簇索引,也即聚集索引。而在主键不存在的情况下,InnoDB存储引擎会隐式的给我们创建一个“伪主键”,然后,创建聚簇索引。

至于非聚簇索引则简单了许多,通过主键以外的列值构建的B+树索引就被称为非聚簇索引。

索引的创建方式

通常来说,索引可以分为四类:主键索引、唯一索引、普通索引、全文索引。

创建主键索引

  • 在创建表的时候,直接在字段名后面指定primary key
    • create table user(id int primary key, name varchar(11), tel varchar(15));
  • 在创建表的最后,指定某列或某几列为主键索引
    • create table user(id int, name varchar(11), tel varchar(15), primary key(id, name));
  • 创建表以后再添加主键索引
    • create table user(id int, name varchar(11), tel varchar(15));
    • alter table user add primary key(id);

主键索引的特点:

  • 一个表中,最多有一个主键索引
  • 主键索引的效率高
  • 创建主键索引的列,其值不能为null,且不能重复
  • 主键索引的列基本上都是int

创建唯一索引

  • 在表定义时,某一列可以直接指定unique属性
    • create table user(id int, name varchar(11) unique, tel varchar(15));
  • 创建表的最后,指定某列或某几列为唯一索引
    • create table user(id int, name varchar(11), tel varchar(15),unique(id, name));
  • 创建表最后再添加唯一索引
    • create table user(id int, name varchar(11), tel varchar(15));
    • alter table user add unique(id);

唯一索引的特点:

  • 一个表可以有多个唯一索引
  • 唯一索引查询效率高
  • 如果指定某一列为唯一索引,则该列不能有重复值,空值除外
  • 如果一个唯一索引指定为not null,则它可以等价为主键索引

创建普通索引

  • 创建表的最后,指定某列为普通索引
    • create table user(id int, name varchar(11), tel varchar(15),index(id));
  • 创建表最后再添加普通索引
    • create table user(id int, name varchar(11), tel varchar(15));
    • alter table user add index(id);
  • 创建一个索引名为 idx_name 的索引
    • create table user(id int, name varchar(11), tel varchar(15));
    • create index idx_name on user(id);

普通索引的特点:

  • 一个表中可以有多个普通索引
  • 如果某个列需要创建索引,但是该列有重复的值,那么就使用普通索引

全文索引

当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。MySQL提供全文索引机制,但是有要求,要求表的存储引擎必须是MyISAM,而且默认的全文索引支持英文,不支持中文。如果对中文进行全文检索,可以使用sphinx的中文版(coreseek)。

索引创建原则

  • 频繁作为查询条件的字段应该作为索引
  • 唯一性太差的字段不适合作为索引
  • 更新频繁的字段不适合作为索引
  • 不会出现再where子句中的字段不该创建索引