1.mysql表单行建议不要超过2000万数据。
测试时候插入mysql数据可以使用mysql伪列rownum插入数据
select (@i:=@i+1) as rownum, person_name from person, (select @i:=100) as init;
set @i=1;
设置临时表的 大小
SET GLOBAL tmp_table_size =51210241024; (512M)
SET global innodb_buffer_pool_size= 110241024*1024 (1G);
innodb索引使用B+Tree,数据表放在数据库文件person.ibd 中 也叫表空间,真正存储的数据结构会拆分多个页存储数据
每个数据页16K
image.png
因为一个页大小有限最多16K那么他会存一些自己的业务数据比如数据指向和一些自己的业务数据
image.png
在页的 7 个组成部分中,我们自己存储的记录会按照我们指定的行格式存储到 User Records 部分。
但是在一开始生成页的时候,其实并没有 User Records 这个部分,每当我们插入一条记录,都会从 Free Space 部分,也就是尚未使用的存储空间中申请一个记录大小的空间划分到 User Records 部分,当 Free Space 部分的空间全部被 User Records 部分替代掉之后,也就意味着这个页使用完了,如果还有新的记录插入的话,就需要去申请新的页了。这个过程的图示如下。
image.png按照上面逻辑,如果数据小可以把所有页都加载到内存然后一个页一个页的判断。实际上数据大是不能这样做,所以为了解决这个问题出现了索引的解决方案。
索引
在 mysql 中索引的数据结构和刚刚描述的页几乎是一模一样的,而且大小也是 16K, 但是在索引页中记录的是页 (数据页,索引页) 的最小主键 id 和页号,以及在索引页中增加了层级的信息,从 0 开始往上算,所以页与页之间就有了上下层级的概念。
层级页图就是B+Tree的结构
非叶子节点存储是的页的指向、叶子节点存的是数据都是顺序的
非叶子节点的id是页的最小值~~~
如图
image.png
数据查找
image.png
比如说我们需要查找一个 id=6 的行数据,因为在非叶子节点中存放的是页号和该页最小的 id,所以我们从顶层开始对比,首先看页号 10 中的目录,有 [id=1, 页号 = 20],[id=5, 页号 = 30], 说明左侧节点最小 id 为 1,右侧节点最小 id 是 5;6>5, 那按照二分法查找的规则,肯定就往右侧节点继续查找,找到页号 30 的节点后,发现这个节点还有子节点(非叶子节点),那就继续比对,同理,6>5&&6<7, 所以找到了页号 60,找到页号 60 之后,发现此节点为叶子节点(数据节点),于是将此页数据加载至内存进行一一对比,结果找到了 id=6 的数据行。
关键点是上层的结点会记录下层的结点的id区间 这样才可以用2分法查找
所以,同样一个 16K 的页,非叶子节点里的每条数据都指向新的页,而新的页有两种可能
如果是叶子节点,那么里面就是一行行的数据
如果是非叶子节点的话,那么就会继续指向新的页
假设
非叶子节点内指向其他页的数量为 x
叶子节点内能容纳的数据行数为 y
B+ 数的层数为 z
如下图中所示
Total =x^(z-1) *y 也就是说总数会等于 x 的 z-1 次方 与 Y 的乘积。
image.png
X =?
在文章的开头已经介绍了页的结构,索引也也不例外,都会有 File Header (38 byte)、Page Header (56 Byte)、Infimum + Supermum(26 byte)、File Trailer(8byte), 再加上页目录,大概 1k 左右,我们就当做它就是 1K, 那整个页的大小是 16K, 剩下 15k 用于存数据,在索引页中主要记录的是主键与页号,主键我们假设是 Bigint (8 byte), 而页号也是固定的(4Byte), 那么索引页中的一条数据也就是 12byte; 所以 x=15*1024/12≈1280 行。
Y=?
叶子节点和非叶子节点的结构是一样的,同理,能放数据的空间也是 15k;但是叶子节点中存放的是真正的行数据,这个影响的因素就会多很多,比如,字段的类型,字段的数量;每行数据占用空间越大,页中所放的行数量就会越少;这边我们暂时按一条行数据 1k 来算,那一页就能存下 15 条,Y≈15。
根据上述的公式,Total =x^(z-1) y,已知 x=1280,y=15
假设 B+ 树是两层,那就是 Z =2, Total = (1280 ^1 )15 = 19200
假设 B+ 树是三层,那就是 Z =3, Total = (1280 ^2) *15 = 24576000 (约 2.45kw)
哎呀,妈呀!这不是正好就是文章开头说的最大行数建议值 2000w 嘛!对的,一般 B+ 数的层级最多也就是 3 层,你试想一下,如果是 4 层,除了查询的时候磁盘 IO 次数会增加,而且这个 Total 值会是多少,大概应该是 3 百多亿吧,也不太合理,所以,3 层应该是比较合理的一个值。
假设mysql一条数据占用空间是5K那么一个页就放下3条数据那么Y就是3所以数据就是500万左右 所以还是需要参考数据存放大小
我们刚刚在说 Y 的值时候假设的是 1K ,那比如我实际当行的数据占用空间不是 1K , 而是 5K, 那么单个数据页最多只能放下 3 条数据
同样,还是按照 Z=3 的值来计算,那 Total = (1280 ^2) *3 = 4915200 (近 500w)
最终2000万是理想情况下的。
网友评论