InnoDB引擎中的索引与算法9
5.1 InnoDB支持以下几种常见的索引:
- B+树索引
- 全文索引
- 哈希索引(自适应哈希索引)
- 关于哈希索引的说明:
-- 1、InnoDB的哈希索引是自适应的,其根据表的使用情况自动生成哈希索引,不能人为干预是否在一张表中生成哈希索引。
-- 2、自适应哈希索引是由InnoDB自己控制的,可以通过innodb_adaptive_hash_index来禁用或者启动此特性,默认为开启。
-- 3、而你在建立索引时,选择的索引方法中有B+tree 和 hash, 这里的hash并不是真的hash索引,实际还是Btree索引,
-- 以下为例子:
CREATE TABLE `test_hash` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `hash_index` (`email`) USING HASH,
KEY `B_index` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DDL中是HASH索引,然而我们通过 SHOW INDEXES FROM test_hash; 命令查询可以看到其index_type为BTREE。
- 关于B+树索引的说明:
1、B+树索引就是传统意义上的索引,是目前关系型数据库中查找最为常用和最有效的索引。B+树索引的构造类似于二叉树,根据键值(Key Value)快速找到数据。
2、B+树中的B不是代表二叉(binary),而是代表平衡(balance),B+树是从最早的平衡二叉树演化而来,但B+树不是一个二叉树。
3、B+树索引并不能找到一个给定键值的具体行,能找到的只是该数据行所在的页。然后数据库把页读到内存中,在内存中查找到需要的数据。
5.2 数据结构与算法
接下来会介绍一些与B+树索引相关的算法与数据结构,以帮助大家更好的理解B+树索引的工作方式。
5.2.1 二分查找法
- 二分查找也称为折半查找法,用来查找一组有序的记录数组中的某个记录,其基本思想是:将记录按照有序化(递增或递减)排列,在查找过程中先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。
- 如有5、10、19、21、31、37、42、48、50、55这10个数,先要从这10个数中查找48这条记录,其查找过程如图5-1所示。
- 从图5-1可以看出,用了3次就找到了48这个数,如果是顺序查找,则需要8次。因此二分查找法的效率要比顺序查找法好(平均的来说)。但如果说查5这条记录,顺序查找只需1次,二二分查找需要4次。对于上面10个数来说,平均查找次数为(1+2+3+4+5+6+7+8+9+10)/10=5.5次。而二分查找法为(4+3+2+4+3+1+4+3+2+3)/10=2.9次。但最坏的情况下,顺序查找需要10次,而二分查找需要4次。
- 二分查找法的应用及其广泛,而且它的思想易于理解。Page Directory 中的槽是按照主键的顺序存放的,对于某一条具体记录的查询时通过对Page Directory进行二分查找得到的,官网中是这样说的:Mysql在定位到Page后在根据slot进行二分查找。
5.2.2 二叉查找树和平衡二叉树
在介绍B+树前,需要先了解一下二叉查找树。B+树是通过二叉查找树,再由平衡二叉树,B树演化而来。二叉查找树是一种经典的数据结构。图5-2显示了一颗二叉查找树。
在二叉查找树中,左子树的键值总小于根的键值,右子树的键值总大于根的键值。因此可以通过中序遍历得到键值的排序输出,图5-2的二叉查找树经过中序遍历后输出:2、3、5、6、7、8.
对于图5-2,如查找5,先找到根,根键值为6大于5,因此查找6的左子树,找到3;而5大于3,再找右子树;一共找了3次。如果按2、3、5、6、7、8的顺序来找同样需要3次。用同样的方法再次查找键值为8的记录,这次用了3次查找,而顺序查找需要6次。计算平均查找次数可得:顺序查找的平均查找次数为(1+2+3+4+5+6)/6=3.3次, 二叉查找树的平均查找次数为(3+3+3+2+2+1)/6=2.3次。二叉查找树的平均查找速度比顺序查找更快。
二叉查找树可以任意的构造,同样是2、3、5、6、7、8这五个数字,也可以按照图5-3的方式建立二叉查找树。
图5-3的平均查找次数为(1+2+3+4+5+5)/6=3.16次,和顺序查找差不多。显然这可二叉查找树的效率就比较低了。因此弱项最大性能地构造一颗二叉查找树,需要这颗二叉查找树是平衡的,从而引出了新的定义 —— 平衡二叉树,或称为AVL树。
平衡二叉树的定义如下:首先符合二叉查找树的定义,其次必须满足任何节点的两个子树的高度最大差为1。显然,图5-3不满足平衡二叉树的定义,而图5-2是一颗平衡二叉树。当然性能最高的不是平衡二叉树,而是最优二叉树,但最优二叉树的建立与维护需要大量的操作,因此,一般我们只需建立一颗平衡二叉树即可。
平衡二叉树的查询速度的确很快,但是维护一颗平衡二叉树的代价是非常大的。通常来说,需要1次或多次的左旋和右旋来得到插入或更新后树的平衡性。对于图5-2所示的平衡术,当用户需要插入一个新的键值为9的节点时,需做图5-4所示的变动。
这里通过一次左旋操作就将插入后的树重新变为平衡的了。但是有的情况可能需要旋转多次,如图5-5所示。
【左旋转】
也就是逆时针旋转两个节点,使父节点被自己的右孩子取代,而自己成为自己的左孩子【右旋转】
顺时针旋转两个节点,使得自己的父节点被左孩子取代,而自己成为自己的右孩子插入、更新和删除操作类似,都是通过左旋右旋来完成的。因此对一颗平衡树的维护是有一定开销成本的,不过平衡二叉树多用于内存结构的对象中,因此维护的开销相对较小。相对而言,B-树结构是为磁盘或者其他直接存取的辅助设备设计的一种平衡查找树
B-树 (读作B树)
从算法逻辑上来讲,二叉查找树的查找速度和比较次数都是最小的。但是二叉树的高度要比B-树高,在mysql中,树的高度代表了磁盘IO的次数。
数据库索引是存储在磁盘上的,当数据量比较大的时候,索引的大小可能有几个G甚至更多,要知道现在innodb默认设置数据与索引存储在同一个.idb文件中。
当我们利用索引查询的时候,显然不可能将整个索引加载到内存中,只能逐一加载每个磁盘页,这里的磁盘页对应着索引树的节点。
刚才我们讲了树的高度代表了磁盘IO的次数,所以我们就需要把原本“瘦高的”树结构变得“矮胖”。这就是B-树的特征之一。
B-树是一种多路平衡查找树,它的每一个节点最多包含k个孩子,K被称为B-树的阶。K的大小取决于磁盘页的大小。
一个m'阶的B-数具有如下几个特征:
- 1、根节点至少有两个孩子。
- 2、每个中间节点都包含K-1个元素和K个孩子,其中m/2 <= k <=m
- 3、每一个叶子节点都包含K-1个元素,其中 m/2 <= k <= m
- 4、所有的叶子节点都位于同一层
- 5、每个节点中的元素从小到大排列,节点当中的k-1个元素正好是K个孩子包含的元素的值域划分。
下面看一个B-树
- 这颗树中,咱们重点来看(2,6)节点。该节点有两个元素2和6,又有三个孩子1,(3,5),8。其中1小于元素2,然后(3,5)在元素2,6之间,8大于6.
- 下面来演示下B-树的查询过程,假如我们要查找的数值是5
整个流程可以看出, B-树在查询中的比较次数并不比二叉树少,尤其当单一节点中的元素数量很多时。
可是相比磁盘IO的速度,内存中的比较耗时几乎可以忽略。所以只要树的高度足够低,IO的次数就足够少,就可以提升查找性能。
节点内部的元素多一些也没有关系,仅仅是多了几次内存交互,只要不超过磁盘页的大小即可。这就是B-树的优势之一。
切换节点,相当于从磁盘中新取出一页数据加载到内存中,而比较大小就是在内存中直接比较就可以了。
B-树插入新节点
- B-树的插入新节点比较复杂,而且分很多情况,这里我们只将一个最典型的例子,假设我们要插入的值是4
- 自顶向下查找4的节点位置,发现4应当插入到节点元素3,5之间。
节点3,5已经是两元素节点,无法再增加。父亲节点 2, 6 也是两元素节点,也无法再增加。根节点9是单元素节点,可以升级为两元素节点。于是拆分节点3,5与节点2,6,让根节点9升级为两元素节点4,9。节点6独立为根节点的第二个孩子。
虽然很麻烦,但B-树始终能维持多路平衡,这也是B-树的一大优势:自平衡
B-树的删除
同样只举一个最经典的例子,删除 11
首先,自顶向下查找元素11的节点位置。
删除11后,节点12只有一个孩子,不符合B树规范。因此找出12,13,15三个节点的中位数13,取代节点12,而节点12自身下移成为第一个孩子。(这个过程称为左旋)
B-树主要应用于文件系统以及部分数据库索引,比如MongoDB。
大部分关系型数据库,比如MySQL使用B+树作为索引。
B+树
- B+树和二叉树、平衡二叉树一样,都是经典的数据结构。
B+树是基于B-树的一种变体,有着比B-树更高的查询性能,一个m阶的B+树有如下几个特征。
1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
从图中我们可以发现,每个父节点的元素都会出现在子节点中,是子节点的最大(或最小)元素。
根节点的最大元素(是15),也就等同于整个B+树的最大元素。以后无论插入删除多少元素,始终要保持最大元素在根节点中。
由于父节点都会出现在子节点,所以叶子节点中包含了所有元素的信息,并且每个叶子节点都有指向下一个节点的指针,形成了有序链表。
相对比B-数,B+数只有叶子节点才有卫星数据,而B-树中所有节点都包含卫星数据。B+树中的中间节点仅仅是索引,没有任何数据关联。
卫星数据是:指的是索引元素所指向的数据记录,比如数据库中的某一行。
innoDB中的聚集索引和非聚集索引虽然都是B+树结构,但是还有区别:
- 聚集索引中,叶子节点直接包含卫星数据(可以直接获取到数据)
- 非聚集索引中,叶子节点带有指向卫星数据的指针 (需要根据指针再去查询)
B+树的好处主要体现在查询性能上。
查询过程跟B-树一样,但是B+树的中间节点只是索引没有数据,所以同样大小的磁盘页可以容纳更多的节点元素。这意味着,数据量相同的情况下,B+树的结构更加“矮胖”,因此IO次数会更少。
其次B+树的查询比如最终查找到叶子节点,而B-树只要找到匹配元素即可,因此B-树的查找性能并不稳定,B+树的性能是稳定的。
再看范围查询,B-树如何做范围查询呢?只能靠中序遍历,而B+树就不一样了,直接在叶子节点的链表上遍历即可。
综上所述:B+树比B-树的IO次数更少,性能更稳定,范围查询更便利。 至于删除跟B-树大同小异,主要还是左旋右旋。
InnoDB引擎中的索引与算法9的更多相关文章
- 聊一聊 InnoDB 引擎中的索引类型
索引对数据库有多重要,我想大家都已经知道了吧,关于索引可能大家会对它多少有一些误解,首先索引是一种数据结构,并且索引不是越多越好.合理的索引可以提高存储引擎对数据的查询效率. 形象一点来说呢,索引跟书 ...
- InnoDB 引擎中的索引类型
首先索引是一种数据结构,并且索引不是越多越好.合理的索引可以提高存储引擎对数据的查询效率. 形象一点来说呢,索引跟书本的目录一样,能否快速的查找到你需要的信息,取决于你设计的目录是否合理. MySQL ...
- 聊一聊 InnoDB 引擎中的这些索引策略
在上一篇中,我们简单的介绍了一下 InnoDB 引擎的索引类型,这一篇我们继续学习 InnoDB 的索引,聊一聊索引策略,更好的利用好索引,提升数据库的性能,主要聊一聊覆盖索引.最左前缀原则.索引下推 ...
- Innodb引擎中Count(*)
select count(*)是MySQL中用于统计记录行数最常用的方法,count方法可以返回表内精确的行数. 在某些索引下是好事,但是如果表中有主键,count(*)的速度就会很慢,特别在千万记录 ...
- 为什么 select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?
统计一张表的总数量,是我们开发中常有的业务需求,通常情况下,我们都是使用 select count(*) from t SQL 语句来完成.随着业务数据的增加,你会发现这条语句执行的速度越来越慢,为什 ...
- MySQL InnoDB引擎B+树索引简单整理说明
本文出处:http://www.cnblogs.com/wy123/p/7211742.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...
- MySQL查看 InnoDB表中每个索引的高度
我们都知道MySQL里,索引通常用B+树来实现的.B+树的叶子结点才具体保存数据(聚簇索引保存的是行数据:普通索引是主键,如有需要得回表),非叶子结点都是用来索引叶子结点的.假设索引高度为h,那么每次 ...
- 【Mysql】InnoDB 引擎中的数据页结构
InnoDB 是 mysql 的默认引擎,也是我们最常用的,所以基于 InnoDB,学习页结构.而学习页结构,是为了更好的学习索引. 一.页的简介 页是 InnoDB 管理存储空间的基本单位,一个页的 ...
- 一分钟掌握MySQL的InnoDB引擎B+树索引
MySQL的InnoDB索引结构采用B+树,B+树什么概念呢,二叉树大家都知道,我们都清楚随着叶子结点的不断增加,二叉树的高度不断增加,查找某一个节点耗时就会增加,性能就会不断降低,B+树就是解决这个 ...
随机推荐
- idea中Lombok的Buider构造器模式,getter/setter正确使用方法
public class ApiUser implements Serializable { private Long id; /*** * 用户类型:single,org(organization) ...
- Jsoup-基础练习
认识Jsoup 一个解析网页的工具 无论你用什么语言爬虫,都要解析网页,今天,我们用一款常用的网页解析Jsoup,来开启爬虫的第一课 认识网页,认识爬虫,认识你自己 *** 快速上手 了解一个新东西最 ...
- 超详细的RNN代码实现(tensorflow)
一.学习单步的RNN:RNNCell 如果要学习TensorFlow中的RNN,第一站应该就是去了解“RNNCell”,它是TensorFlow中实现RNN的基本单元,每个RNNCell都有一个cal ...
- charles 开始/暂停记录
本文参考:charles 开始/暂停记录 1.1. stop/start recording 和 2.1 recording settings 是常用的功能了:这里需要注意就是后面的session1代 ...
- 【数据库开发】在Windows上以服务方式运行 MSOPenTech/Redis
在Windows上以服务方式运行 MSOPenTech/Redis ServiceStack.Redis 使用教程里提到Redis最好还是部署到Linux下去,Windows只是用来做开发环境,现在这 ...
- 跨域及jsonp
什么是跨域? 要解释跨域,就要先说明下什么是域?域的英文名是Domain,百度百科给的定义是: 域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust ...
- 《Mysql - 事务 MVCC》
一:前言 - 前面通过 <Mysql 事务 - 隔离> 的学习,知道了事务的实现,是根据 获取一致性视图 来实现的. 二:那么,什么时候会获取到一致性视图呢? - 例如:有三个事务,启动的 ...
- 数据库数据生成Excel表格(多用在导出数据)
最近在项目开发中遇到这样一个需求,用户聊天模块产品要求记录用户聊天信息,但只保存当天的,每天都要刷新清空数据,但聊天记录要以Excel的形式打印出来,于是就引出了将数据库的数据导出成Excel表格的需 ...
- C++之父给 C 程序员的建议
1. 在 C++中几乎不需要用宏, 用 const 或 enum 定义显式的常量, 用 inline 避免函数调用的额外开销,用模板去刻画一族函数或类型,用 namespace 去避免命名冲突. 2. ...
- 理解Python函数和方法
什么是函数? 函数是抽象出的一组执行特定功能的重复代码,通俗理解,就是对一些重复的工作进行封装和然后直接调用,避免重复造轮子. Python中的函数如何定义? 使用def关键字,结构如下: def 函 ...