前言
- MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等。本文只关注于BTree索引。
数据结构及算法基础
索引的本质
-
索引的定义:索引是一类数据结构,用于帮助MySQL高效的获取数据。sql
数据库系统维护着知足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就能够在这些数据结构上实现高级查找算法。这种数据结构,就是索引。数据库
上图展现了一种可能的索引方式:左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并非必定物理相邻的)。为了加快Col2的查找,能够维护一个右边所示的二叉查找树,每一个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就能够运用二叉查找在θ(log2n)θ(log2n)的复杂度内获取到相应数据。虽然这是一个货真价实的索引,可是实际的数据库系统几乎没有使用二叉查找树或其进化品种红黑树实现的,缘由在于树的深度太高所致使的IO次数过多。数据结构
经常使用的树型索引
B-Tree
-
B-Tree的定义与特征:B-Tree中的每一个结点都保存一组二元组[key, data],其中key为关键字,data为除key之外的数据。post
- B树又叫平衡多路查找树,一棵m阶的B树有以下特征:
- 根结点有[2,m][2,m]个子树,非根内部结点有[⌈m/2⌉,m][⌈m/2⌉,m]个子树。
- 全部叶子结点(空结点)都出如今同一层。
- 假设每一个非终端结点中包含有n个关键字信息:{p0,k1,p1,k2,p2,...,kn,pn}{p0,k1,p1,k2,p2,...,kn,pn},其中kiki为关键字且关键字按顺序升序排序,pipi为指向子树的结点,则指针pi−1pi−1所指向子树中的全部结点的关键字均处于(ki−1,ki)(ki−1,ki)范围内 —— 最左子树无下限,最右子树无上限。
- B树又叫平衡多路查找树,一棵m阶的B树有以下特征:
B+Tree
- MySQL广泛使用B+Tree实现其索引结构。
-
B+Tree的定义与特征:B+Tree中的每一个内结点都保存一组关键字,而data只存于叶子结点中。性能
- B+树又叫平衡多路查找树,一棵m阶的B+树有以下特征:
- 根结点有[2,m][2,m]个子树,非根内部结点有[⌈m/2⌉,m][⌈m/2⌉,m]个子树。
- 全部叶子结点(保存data的结点)都出如今同一层。
- 假设每一个非终端结点中包含有n个关键字信息:{k1,p1,k2,p2,...,kn,pn}{k1,p1,k2,p2,...,kn,pn},其中kiki为关键字且关键字按顺序升序排序,pipi为指向子树的结点,则指针pipi所指向子树中的全部结点的关键字均处于[ki,ki+1)[ki,ki+1)范围内 —— 最左子树有下限,最右子树无上限。
- B+树又叫平衡多路查找树,一棵m阶的B+树有以下特征:
-
通常在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增长了顺序访问指针。
优化
在B+Tree的每一个叶子节点增长一个指向相邻叶子节点的指针,就造成了带有顺序访问指针的B+Tree。作这个优化的目的是为了提升区间访问的性能,例如上图中若是要查询key为从18到49的全部数据记录,当找到18后,只需顺着节点和指针顺序遍历就能够一次性访问到全部数据节点,极大提到了区间查询效率。atom
B-Tree和B+Tree的主要区别
- B-Tree和B+Tree的主要区别:
- B+Tree中每一个结点内的关键子个数与指针个数相同;而B-Tree中的关键字个数比指针个数少1。
- B+Tree中每一个内节点不存储data(data只存储在叶子结点),只存储key;而B-Tree中每一个结点都存储data。
- B+Tree中的查找都结束于叶子结点;而B-Tree中的查找既可能结束于叶子结点,也可结束于内结点。
B+Tree更适合作外部索引
-
为何B+Tree更适合作外部索引?:
-
数据库系统一般将一个节点的大小设为一个页,这样每一个节点只须要一次I/O就能够彻底载入 —— 所以磁盘IO次数和树的高度成正比。
B-Tree中一次检索最多须要h−1h−1次I/O(根节点常驻内存),即磁盘IO的时间复杂度为θ(h)=θ(logdN)θ(h)=θ(logdN)。
-
B-Tree中每一个内结点都既存关键字也存数据,而B+Tree中每一个内结点只存关键字,所以每一个内结点的关键字个数以下所示,从而B+Tree相对于B-Tree的高度更小,所需的磁盘IO次数更少。
- B-Tree:dd = pagesizepagesize // (keysize+datasize+pointsize)(keysize+datasize+pointsize)
- B+Tree:dd = pagesizepagesize // (keysize+pointsize)(keysize+pointsize)
-
MySQL索引实现
- 在MySQL中,不一样存储引擎对索引的实现方式是不一样的。
MyISAM索引实现
-
MyISAM引擎使用B+Tree做为索引结构,叶节点的data域存放的是数据记录的地址。下图为主索引的结构图:
-
在MyISAM中,主索引和辅助索引在结构上没有任何区别,只是主索引要求key是惟一的,而辅助索引的key能够重复。
InnoDB索引实现
-
InnoDB引擎使用B+Tree做为索引结构,主索引的叶节点的data域存放的是数据记录自己。
-
在InnoDB中,辅助索引的叶结点的data域存放的是对应的主键值,以后在主索引结构中继续查找对应的数据记录。
聚类索引和非聚类索引
-
聚类索引:聚类索引是指数据的物理顺序与键值的逻辑顺序相同。
一个表只能有一个汇集索引,由于一个表的物理顺序只有一种状况,因此对应的聚类索引只能有一个。若是某索引不是汇集索引,则表中的行物理顺序与索引顺序不匹配 —— InnoDB中的主索引就是聚类索引,由于数据内容存于该索引结构叶子结点的data域中。
-
非聚类索引:非聚类索引是数据的物理顺序与键值的逻辑顺序不一样。例如MyISAM的索引以及InnoDB的辅助索引,由于这些索引结构的叶子结点的data域中实际存储的是指向数据内容的指针或主键值。