对比项 | MyISAM | InnoDB |
---|---|---|
主外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即使操作一条记录也会锁住整个表,不适合高并发操作 | 行锁,操作时只锁住某一行,不对其它行有影响,适合高并发操作 |
缓存 | 只缓存索引,不缓存真实数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性影响 |
表空间 | 小 | 大 |
关注点 | 性能 | 事务 |
默认安装 | 是 | 是 |
小结: MyISAM 适合读多写少,InnoDB 适合写多读少
MySQL 官方对索引的定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构,可以得到索引的本质:索引是数据结构
也可以简单地理解为索引是 排好序的快速查找 B+ 树数据结构
B+ 树中的 B 代表的是平衡(balance)而不是二叉(binary)
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。下图是一种可能的索引方式:
画得不是很好,不要介意哈。为了加快 Column 2 的查找,可以维护一个左边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录的物理地址的指针,这样就可以运用二叉查找在一定的复杂度内获取到相应的数据,从而快速的检索出符合条件的记录
加速查找速度的的数据结构,常见的有两类:
可以发现,不管是读请求,还是写请求,哈希类型的索引,都要比树型的索引更快一些,那为什么索引结构要设计成树型呢?
举个例子:假如现在有 16 条数据
如果是使用哈希的话,时间复杂度就是 O(16) = 16,也就是说要查找 16 次才能找到
如果是使用树的话,时间复杂度就是 O(log16) = 4,也就是说查找 4 次就能找到
想想范围 / 排序等其它 SQL 条件
哈希型的索引,时间复杂度会退化为 O(n) 而树型的 “有序” 特性,依然能够保持 O(log2(n)) 的高效率
所以这里总结一下:
InnoDB 并不支持哈希索引
上面说过哈希(hash)比树(tree)更快,那为什么索引结构要设计成树型呢?
中序遍历首先遍历左子树,然后访问根节点,最后遍历右子树。若二叉树为空则结束返回,否则:
从算法的数学逻辑来讲,二叉树的查找速度和比较次数都是最小的,看下下面这个动画
图中有 10 个元素,假如要查找的元素是 10,那么就需要 4 步
但是当插入的数据越来越多的时候,树的高度也会增加,树的高度越高,那么查找的次数就会越多,查找次数越多,那么磁盘 IO 数的量就会越大,导致系统随着数据量的加大,从而系统性能急剧下降
同样的元素,不一样的数据结构,这个数据结构的查找 10 只需 3 步
从 B 树结构 图中看到每个节点中不仅包含数据的 key 值,还有 data 值。而每一个页的存储空间是有限的,如果 data 数据较大时将会导致每个节点(即一个页)能存储的 key 的数量很小,当存储的数据量越大时同样会导致 B 树的深度较大,增大查询时的磁盘 I/O 次数进而影响查询效率
比如我们连接 MySQL 之后输入以下 SQL 语句执行
SHOW GLOBAL STATUS LIKE 'Innodb_page_size'
输出:
Innodb_page_size 俗称磁盘页大小(就跟翻书的一页一页一样),从输出可以发现 Innodb_page_size 大小默认是 16KB
系统从磁盘读取数据到内存时是以 磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会呗一次性读取出来,而不是需要什么取什么
InnoDB 存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位
系统的一个磁盘块的存储空间往往没有这么大,因此 InnoDB 每次申请磁盘空间时都会是 若干个地址连接磁盘块来达到页的大小 16 KB,InnoDB 在把磁盘数据读入到磁盘时会 以页为基本单位,在查询数据的时候如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘 I/O 次数,提高查询效率
每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址
模拟查找关键字 29 的过程:
根据根节点找到磁盘块 1,读入内存【磁盘 I/O 操作第 1 次】
比较关键字 29 在区间(17,35)之间,找到磁盘块 1 的指针 p2
根据 p2 指针找到磁盘块 3,读入内存【磁盘 I/O 操作第 2 次】
比较关键字 29 在区间(26,30)之间,找到磁盘块 3 的指针 p2
根据 p2 指针找到磁盘块 8,读入内存【磁盘 I/O 操作第 3 次】
在磁盘块 8 中的关键字列表中找到关键字 29
根据上面的分析过程,发现需要 3 次磁盘 I/O 操作,和 3 次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而 3 次磁盘 I/O 操作是影响整个 BTree 查找效率的决定因素。BTree 相对于 AVLTree 缩减了节点个数,使每次磁盘 I/O 取到内存的数据都发挥了作用,从而提高了查询效率
B 树比平衡二叉树减少了一次 IO 操作
从图中可以看出所有 data 信息都移动到 叶子节点中,而且子节点和子节点之间会有个指针指向,这个也是 B+ 树的核心点,这样可以大大提升 范围查询效率,也方便遍历整棵树
(1) 非叶子节点不再存储数据,数据只存储在同一层的叶子节点上
(2)叶子之间,增加了 链表 ,获取所有节点,不再需要 中序遍历(上述有讲到过)
在 B+ 树中,所有数据记录节点都是按照键值大小顺序存放在 同一层的叶子节点上,而非叶子节点上只存储 key 值信息,这样可以大大加大每个节点存储的 key 是数量,降低 B+ 树的高度
1、InnoDB 存储引擎的最小存储单元是页,页可以用于存储数据也可以用于存储键值 + 指针,在 B+ 树中叶子节点存放数据,非叶子节点存放键值 + 指针
2、索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,首先找到根页进而再去数据页中查找到需要的数据
B+ 树算法:通过继承了 B 树的特征,B+ 树相比 B 树,新增叶子节点
与非叶子节点关系
叶子节点中包含了键值和数据
非叶子节点中只是包含键值和子节点引用,不包含数据
通过非叶子节点查询叶子节点获取对应的数据,所有相邻的叶子节点包含非叶子节点使用 链表进行结合,叶子节点是顺序排序并且相邻节点有顺序引用的关系
B+ 树是在 B 树基础上的一种优化使其更适合实现外存储索引结构,InnoDB 存储引擎就是使用 B+ 树实现其索引结构