这里我们考虑MySQL的InnoDB存储引擎
这个问题需要从两方面考虑:
- 数据在存储器中的存储组织方式
- InnoDB索引数据结构
首先需要考虑数据在存储器中如何存储:
1、数据持久化存储磁盘里,磁盘的最小单元是扇区,一个扇区的大小是 512个字节
2、文件系统的最小单元是块,一个块的大小是 4KB
3、InnoDB存储引擎的最小存储单元称之为页,一个页的大小是16KB
扇区、块、页这三者的存储关系?
MySQL数据库中,table表中的记录都是存储在页中,那么一页可以存多少行数据?
假设一行数据的大小约为1K字节,那么按 16K / 1K = 16,可以计算出一页大约能存放16条数据。
MySQL的最小存储单元叫做“页”,这么多的页是如何构建一个庞大的数据组织,我们又如何知道数据存储在哪一个页中?为了提升查找速度,InnoDB引入了B+树来进行数据的组织存储。B+树分为了叶子节点和非叶子节点,其中叶子节点存放数据,非叶子节点存放键值和指针。这样的数据组织形式,我们称为索引组织表。
B+树的非叶子节点的页存放键值和指向数据页的指针,这样的页由N个键值+指针组成
一棵树可以存放多少条数据?
假设B+树的深度为2
这棵B+树的存储总记录数 = 根节点指针数 * 单个叶子节点记录条数
假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节。
那么一个页中能存放多少这样的组合,就代表有多少指针,即 16384 / 14 = 1170。那么可以算出一棵高度为2 的B+树,能存放 1170 * 16 = 18720 条这样的数据记录。
同理:
高度为3的B+树可以存放的行数 = 1170 * 1170 * 16 = 21902400
千万级的数据存储只需要约3层B+树,查询数据时,每加载一页(page)代表一次IO。所以说,根据主键id索引查询约3次IO便可以找到目标结果。
实战
实际项目中,每个表的结构设计都不一样,占用的存储空间大小也各不相等。如何计算不同的B+树深度下,一个表可以存储的记录条数?
假设当前表的行平均大小为153个字节。
计算过程:
单个叶子节点(页)中的记录数 = 16K / 153 = 105
非叶子节点能存放多少指针, 16384 / 14 = 1170
如果树的高度为3,可以存放的记录行数 = 1170 * 1170 * 105 = 143,734,500