为什么都动不动就说mysql数据库单表最大两千万?依据是啥???

这两千万其实是一个建议值,先来看一下这2000w怎么来的:
MYSQL为了提升查询速度,内部使用B+Tree作为索引
假设有一张user表,如下图:

其id是唯一主键,每一行数据暂且称之为"行数据",看起来就像个Excel表一样,Excel的数据在硬盘上其实放在了一个为user.xls的文件中

而上面MYSQL的user表中数据在硬盘上也类似,放在了user.idb文件中,指user innodb data文件,专业点来说叫表空间,虽然在数据表中看起来这些"行数据"是挨在一起的

但实际在user.idb文件中,被分成了很多小份的数据页

每份大小16k,因为行数据被分成了很多份,并放到了很多个数据页里面,为了标识具体是哪一页,引入页号的信息

为了把这些数据页关联起来,引入了前后指针,用于指向前后的数据页

这些信息加到了数据页的页头中

数据页是需要读写的,16k说小不小,写到一半,电源线被拔了也是有可能的,所以为了保证数据页的正确性,还引入了校验码,在页尾中。

也就是说把页头页尾掐掉,对 没错,像🦐一样 掐头去尾,剩下的空间才是用来放行数据的。

如果行数据行数特别多的话,进到页里挨个遍历效率也低,所以为这些数据生成个页目录,具体实现不重要,记住,它可以通过二分查找的方式将效率从o(n)变成了o(logn)

如果想查一条行数据,可以把表空间里的每一页都拿出来挨个判断里面的行数据,是不是我们要做好的,行数据量小的时候,这么操作是没什么问题的,行数据大了性能就慢了,因为每次查找都有可能遍历所有的行数据

为了加速搜索,在每个数据页里选出主键id最小的行数据,而且只需要他们的主键id以及所在页的页号,将它们组成新的行数据,放到一个新生成的数据页中

这个新生成的数据页和之前的页结构没什么太大的区别,并且大小也是16k,同时为了跟之前的数据页区分,新数据页要加入页层级的信息,于是数据页之间就有了上下层级的概念,如上图,就像是一棵倒过来的树,也就是常说的B+Tree,最下面的一层就是所谓的叶子节点,其余的都叫非叶子节点。

比如我们想查id为2的数据,会先查非叶子节点,发现向左id最小是1,向右最小id是4,那么 id=2的数据如果存在,必定在左边箭头下面

于是磁盘加载左下角的数据页在数据页中找到id=2的行数据。

之前展示的是2层的树,如果数据变多了,通过类似的方法,再往上构建一层,就形成了三层树,如下图:

需要注意的是,数据页的页号并不是连续的,他们在磁盘里也不一定挨在一起。

如果查询过程中两个页都在磁盘中,那么最多需要两次磁盘IO,它们才能被拿到内存。

接下来 重点!!!

2000w的说法怎么来的

同样一个16k的页,B+树最未级节点里放了行数据,而非叶子节点则用来放了加速查询的索引数据,用来指向其他16k的数据页。

假设 指向其他非叶子节点里指向其他内存页的指针数量为x,叶子节点里容纳的行数据数量为y,层数为z,B+Tree里能存放的行数据总量

假设掐头去尾,大概剩下15k用来存放索引数据,每条索引数据主要由主键和指向页号组成,主键假设是bigint大小 8byte,页号叫PAGE_NUMBER 大小4byte,那非叶子节点里的每一条数据就是12byte左右,用15k除以12byte等于1280,也就是说x为1280,叶子节点和非叶子节点数据结构是一样的,假设一条行数据占1k,那么一个数据页能放15行,y等于15,假设树是2层 z等于2,那么数据表的总行数就是2w,

假设树的3层,那么数据表的总行数就是2.5w,这个2.5w就是单表最大行数2000w的由来,在加一层数据就大的有点离谱,3层数据页最多对应3次io,还算合理,那么超过2000w就慢了么,假如我单行数据用不了1k这么多,比如只用了250byte,那么单个数据页就能放60条数据,同样是3层树,单表支持的行数就能到1亿,最多也就3次IO,所以并不慢。

单行数据1k,2层就是2千万数据。如果单行数据小于1k,单表就可以超过2千万。主要看单行数据大小

mysql性能下降最根本的原因是内存hold不住高频数据了;树高带来的性能影响忽略不计。
因为mysql的非叶子节点基本都是在内存里面的,叶子节点才会经常被淘汰,如果业务整体高频数据太多了,此时mysql为了腾出内存会频繁触发刷脏,从而影响其它查询走的是磁盘io这时候效率就很慢了,从这里也可以知道讨论mysql性能要从整体去看,而不是动不动就拿单表数据量说事,阿里巴巴规范固然很好但也不能无脑,分库分表能不用就不用,因为用好的人不多,切记,架构简单是设计原则

B+Tree

聚簇索引

  • 叶子节点:存储的是整行数据。
  • 非叶子节点:存储的是索引值(即主键值),这些值用于指导查询过程中的搜索方向。

非聚簇索引

  • 叶子节点:存储的是主键的值,而不是整行数据。这是因为非聚簇索引的目的是加速查询,而不是直接提供数据。当通过非聚簇索引找到主键值后,MySQL会进行所谓的“回表”操作,即根据主键值去聚簇索引中查找相应的整行数据。
  • 非叶子节点:同样存储的是索引值(即非主键索引列的值),这些值也用于指导查询过程中的搜索方向。

mysql里面每次新建索引都会生成新的B+树,这也是索引文件会随着索引字段不断增加的原因

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值