MySQL索引原理

什么是索引?

“索引”是为了可以更快地查询数据。好比一本书的目录,就是这本书的内容的索引,读者能够经过在目录中快速查找本身想要的内容,而后根据页码去找到具体的章节。数据库

数据库也是同样,若是查询语句使用到了索引,会先去索引里面查询,取得数据所在行的物理地址,进而访问数据。数据结构

索引的优缺点

优点:以快速检索,减小I/O次数,加快检索速度;根据索引分组和排序,能够加快分组和排序;函数

劣势:索引自己也是表,所以会占用存储空间。索引的维护和建立须要时间成本,这个成本随着数据量增大而增大;构建索引会下降数据表的修改操做(删除,添加,修改)的效率,由于在修改数据表的同时还须要修改索引表。性能

索引的分类

在MySQL中,常见的索引类型有:主键索引、惟一索引、普通索引、全文索引、组合索引。建立语法分别为:优化

建立索引.png

其中,组合索引又称为多列索引,上述代码中最后一个例子就是创建了3列的索引。MySQL在根据索引查询时,会遵循“最左匹配”原则,即先根据col1的条件查,再根据col2的条件查,而后再根据col3的条件去查。操作系统

若是跳过了一个列直接查后面的列,好比下面的语句,就不能使用上面建立的索引了:插件

语句.png

这里有一个小技巧,若是你前面的列是一个简单的枚举类型,好比性别等,能够用在where语句中加 col1 in(MALE, FEMALE) 来“跳过” col1 列,并使用上述索引。设计

对于某列若是是字符串且比较长(好比UUID),推荐使用前缀索引,即匹配前n个字符。具体这个n取值多少是根据你的数据来的,《高性能MySQL》里提供了一个技巧:经过使用LEFT函数查询,从1开始,不断增长n的值,直到查询结果的行数接近完整列的查询结果的行数,就是合适的n的值。3d

前缀索引.png

索引的实现原理

MySQL的索引是由存储引擎来实现的。因为存储引擎不一样,因此具备不一样的索引类型,如BTree索引,B+Tree索引,哈希索引,全文索引等。这里因为主要介绍BTree索引和B+Tree索引,咱们平时使用最多的InnoDB引擎就是基于B+Tree索引的。指针

目前版本的MySQL InnoDB引擎已经支持全文索引,但不支持中文,能够经过使用ngram插件开始支持中文。

从二叉搜索树聊起

了解过数据结构的朋友应该知道一种叫二叉树的数据结构。二叉树根据用途不一样,衍生了不一样的变种,好比堆,好比二叉搜索树。

而二叉搜索树中,为了防止极端状况树的高度过大影响查询效率,因此衍生出了一些平衡二叉查找树,最典型的就是AVL和红黑树。

但二叉树在数据量较大时,深度过深,不太适合数据库的查询,因此数据库使用了多叉树。

BTree

BTree(又称为B-Tree)是一个平衡搜索多叉树。BTree的结构以下图:

BTree

设树的度为2d(d>1),高度为h,那么BTree有如下性质:

  • 每一个叶子结点的高度同样,等于h;
  • 每一个非叶子结点由n-1个key和n个指针组成,key和指针相互隔离,结点两端必定是key;
  • 叶子结点指针为null;
  • 非叶子结点的key都是[key,data]二元组,其中key表示做为索引的键,data为键值所在行的其它列的数据;

在BTree中,对索引列是顺序存储的,因此很适合查找范围数据和ORDER BY操做。

B+Tree

B+Tree是BTree的一种变种。B+Tree和BTree的不一样主要在于:

  • B+Tree中的非叶子结点不存储数据,只存储键值;
  • B+Tree的叶子结点没有指针,全部键值都会出如今叶子结点上,且key存储的键值对应data数据的物理地址;
  • B+Tree的每一个非叶子节点由n个键值key和n个指针point组成;

结构图:

B+Tree

B+Tree对比BTree的优势:

通常来讲B+Tree比BTree更适合实现外存的索引结构,由于存储引擎的设计专家巧妙的利用了外存(磁盘)的存储结构。

磁盘的最小存储单位是扇区(sector),而操做系统的块(block)一般是整数倍的sector,操做系统以页(page)为单位管理内存,一页(page)一般默认为4K,数据库的页一般设置为操做系统页的整数倍,所以索引结构的节点被设计为一个页的大小,而后利用外存的“预读取”原则,每次读取的时候,把整个节点的数据读取到内存中,而后在内存中查找。

已知内存的读取速度是外存读取I/O速度的几百倍,那么提高查找速度的关键就在于尽量少的磁盘I/O,那么能够知道,每一个节点中的key个数越多,那么树的高度越小,须要I/O的次数越少,所以通常来讲B+Tree比BTree更快,由于B+Tree的非叶节点中不存储data,就能够存储更多的key。

带顺序索引的B+Tree

通常在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增长了顺序访问指针。

带顺序索引的B+Tree

在B+Tree的每一个叶子节点增长一个指向相邻叶子节点的指针,就造成了带有顺序访问指针的B+Tree。作这个优化的目的是为了提升区间访问的性能,例如若是要查询key为从18到49的全部数据记录,当找到18后,只需顺着节点和指针顺序遍历就能够一次性访问到全部数据节点,不用从头再查询一次,极大提到了区间查询效率。

聚簇索引和非聚簇索引

MySQL中最多见的两种存储引擎分别是MyISAM和InnoDB,分别实现了非聚簇索引和聚簇索引。

前段时间看到一个问题:“你知道为何InnoDB非主键索引广泛比主键索引要慢吗?”答案是InnoDB使用了聚簇索引,主键索引主须要查询一次,而非主键索引须要查询两次。

为何非主键索引须要查询两次呢?且看接下来的内容。

主索引与辅助索引

首先介绍一下基础的概念。在索引的分类中,咱们能够按照索引的键是否为主键来分为“主索引”和“辅助索引”,使用主键键值创建的索引称为“主索引”,其它的称为“辅助索引”。所以主索引只能有一个,辅助索引能够有不少个。

为何须要用到辅助索引?由于前面咱们介绍了,查询语句若是想要使用索引,是须要知足最左匹配原则的。有时候咱们的查询并不会使用到主键列,因此须要在其它列创建索引,即辅助索引。

非聚簇索引

非聚簇索引的主索引和辅助索引几乎是同样的,只是主索引不容许重复,不容许空值,他们的叶子结点的key都存储指向键值对应的数据的物理地址。

非聚簇索引的数据表和索引表是分开存储的。非聚簇索引中的数据是根据数据的插入顺序保存。所以非聚簇索引更适合单个数据的查询。插入顺序不受键值影响。

聚簇索引

聚簇索引的主索引的叶子结点存储的是键值对应的数据自己,辅助索引的叶子结点存储的是键值对应的数据的主键键值。所以主键的值长度越小越好,类型越简单越好。

聚簇索引的数据和主键索引存储在一块儿。

聚簇索引的数据是根据主键的顺序保存。所以适合按主键索引的区间查找,能够有更少的磁盘I/O,加快查询速度。可是也是由于这个缘由,聚簇索引的插入顺序最好按照主键单调的顺序插入,不然会频繁的引发页分裂(BTree插入时的一个操做),严重影响性能。

在InnoDB中,若是只须要查找索引的列,就尽可能不要加入其它的列,这样会提升查询效率。

一张图说明聚簇索引与非聚簇索引的区别:

聚簇索引和非聚簇索引的区别
相关文章
相关标签/搜索