一 概述
上一篇我们了解了mysql的结构,这篇,叶子就和大家好好聊聊mysql最具特色的功能,存储引擎。
如果还不了解mysql的结构,可以看看叶子的上一篇文章。
浅谈MySQL体系,这下总该懂了吧!
mysql适用于多种复杂的业务场景,不管是增多查少,还是增少查多,亦或者是增多查多,他统统都能满足,那它为什么能做到这一步呢,这就离不开他的存储引擎了。
这里,我们暂时只说5.5版本后默认支持的存储引擎InnoDB。
二 InnoDB是什么?
对各位小伙伴来说,InnoDB存储引擎应该是一点都不陌生的,在MySql 5.5版本后,InnoDB存储引擎就是MySql默认的存储引擎。
它具备以下的特点:
DML操作遵循ACID模型,支持事务。
支持行级锁,提高并发访问性能。
支持外键约束,保证数据的完整性和正确性。
它存储在磁盘上的文件xx.ibd,xx代表的是表名,ibd则是文件后缀,InnoDB引擎每张表都会对应一个表空间文件,存储表的结构,数据和索引。
可以通过查看innodb_file_per_table参数,默认是开启的,即使用InnoDB存储引擎创建的表,默认都会生成对应的ibd文件。
show variables like ‘innodb_file_per_table’;
每一张表都有一个对应的ibd文件,我们直接打开mysql的数据存放目录就可以看到。
ibd文件不仅存放表结构,数据,还会存放该表对应的索引信息,并且这个文件是基于二进制存储的,不能直接打开,我们可以使用mysql提供的一个指令ibd2sdi,就可以从ibd文件中提取sdi的信息,sdi数据字典信息就存放在这个文件中。
InnoDB的逻辑存储结构
在InnoDB存储引擎中,他的内存区域包含表空间,段,区,页,行,如下图所示
表空间 : InnoDB存储引擎逻辑结构的最高层,ibd文件其实就是表空间文件,在表空间中可以包含多个段。
段 : 表空间是由各个段组成的, 常见的段有数据段、索引段、回滚段等。InnoDB中对于段的管理,都是引擎自身完成,不需要人为对其控制,一个段中包含多个区。
区 : 区是表空间的单元结构,每个区的大小为1M。默认情况下, InnoDB存储引擎页大小为16K, 即一个区中一共有64个连续的页。
页 : 页是组成区的最小单元,页也是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性,InnoDB 存储引擎每次从磁盘申请 4-5 个区。
行 : InnoDB 存储引擎是面向行的,也就是说数据是按行进行存放的。
索引就是在存储引擎层实现的,不同的存储引擎有不同的索引结构,常见的有B+Tree索引,Hash索引,以及一些不常见的R-Tree索引(空间索引,是MyISAM中的一种特殊索引,用于地理空间数据,用的较少)
下面,我们要说的,就是InoDB引擎的底层B+Tree索引。
如图所示,这里我采用的五阶,也就是说每个节点最大保存四个Key值,五个指针,超过了,树就会进行分裂,中间元素向上,左小右大,并且,在B+Tree中,非叶子结点不会存放数据,具体的数据都是存放在叶子节点的。
有兴趣的小伙伴可以自己试一下,网址:
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
那为什么说B+Tree高效呢,我们来做一道题,一页存储16kb数据,假设一行数据1kb,主键索引为bigint,占据8个字节,指针占据6个字节,这样计算下来
n * 8+(n+1)*6=16*1024
n=1170
也就是说,树的高度如果为2,那么就是1170*16约等于一万八千多条记录,而到了第三层,则是在二层树的基础上继续乘上1170,数据可达到两千两百多万条,三层的B+树,三次磁盘IO,存储千万条数据,这已经能满足日常大部分业务需求了。
当然,这样计算只是粗略计算,数据页还会存放一些固定的信息,页头,页尾,页目录之类的,大概也能占据1k样子。
最后再说一点,有的小伙伴可能已经想到了,这是基于行数据在1kb或者1kb以下算出来的,如果说行数据过大超过了1kb,甚至是达到了10kb,那三层的B+tree还能存储这么多数据吗,如果能存的话,为什么能存,不能存的话,又该怎么办呢,这些我后续专门写一篇说明吧!
实际上 MySql使用的,并不是原本的B+Tree,而是对B+Tree进行了优化,在原有结构的基础上,叶子结点增加了链表指针,提高了区间访问的性能,利于排序,方便范围查找。
总结
ok,这篇我们了解了InnoDB引擎是干什么用的,以及它的内存模型,它的底层结构B+树,知道了B+树为什么能存储这么多的数据,希望小伙伴们都能所有收获,最后的最后,如果大家喜欢的话,看完记得点赞哦。
欢迎关注叶子的公众号【一叶知求】 更多技术分享都在上面哦!
每日一题:
请用java语言实现一个二叉查找树,小伙伴们可以好好思考下,叶子这边给出一个参考,抛砖引玉。
参考答案:
**
*
* @author yiyezhiqiu
*
* */
public int halfSearch(int[] nums, int target) {
if (nums == null) return -1;
//最左侧数字下标
int left = 0;
//最右侧数字下标
int right = nums.length;
//左边小于右边,则循环一直继续,直到左边等于或者大于右边
while (left < right) {
//初次查找从一半开始
int mid = left + ((right - left) >> 1);
/*
* 目标值小于中间值,则中间值赋给右侧数据,此时数据区间则是从开始到原本数据的中间值,
* 反之,则赋值给左侧值,新数据区间则从原本的中间值到最右侧的值
* */
if (target <= nums[mid]) {
right = mid;
} else {
left = mid + 1;
}
}
if (left < nums.length && nums[left] == target) {
return left;
};
return -1;
}