学软件技术,读第一手资料,去官方网站:MySQL 5.7参考手册
也可以看看比较经典的书籍,如《高性能MySQL》等
1、操作系统的磁盘块(block)
操作系统从磁盘读取数据到内存是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这样做的理论依据是计算机科学中著名的局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。
预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(在许多操作系统中,页的大小通常为4k)。
2、InnoDB存储引擎中的页(Page)
而InnoDB存储引擎中有页(Page)的概念,页是InnoDB磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K。
而一个磁盘块的存储空间往往没有这么大,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。
InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时,如果一个页中的每条数据都能有助于定位数据记录的具体位置,那么将会减少磁盘I/O次数,提高查询效率。
B-Tree和B+Tree 结构的数据可以让系统高效的找到数据所在的磁盘块。
3、举个例子说说MySQL为啥选择B+Tree结构存储索引
二叉树和平衡二叉树,每个节点只有一个key和值,这样当数据量很大的时候,树会很高(也就是很多层,或者叫做很多阶),树的每一个节点都是一次磁盘IO,这样速度就会慢,影响查找性能。
同样是一次磁盘IO,B-Tree和B+Tree 可以读取节点的一组key,甚至是更多。
下面做一个推算:
假如是三层树:
主键longint (8字节btype) + 指针(6字节btype) = 14btype
InnoDB存储引擎中页的大小为16KB 16*1024/ 14 = 1170
假设一行数据是1k,最下页子节点每一页16k就是16个数据,三层总数据是: 1170*1170*16 = 21 902 400 = 2200W
以下备注一个错误的算法,没有考虑主键索引的叶子节点会存储数据
InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),
指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储
16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗^3)。
也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。
(错误,错误,错误,因为没有考虑主键索引叶子节点会存储数据)
实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作。