网上常说mysql单表2kw就需要考虑分表了,但生产中我们也用过2亿的表,而且毫无压力。
所以记录一下为什么2kw就要分表是依据什么原理,生产大概要注意什么。
这里只关注B+树的存储
在MySQL中,为了保存内存地址,通常使用6字节来存储指针。如果使用BigInt作为PK的话,那一个BigInt就是8byte,所以在非叶子结点,一个数据就占用6+8 byte。
在Linux中,数据都是一页一页存储的,一页16k。不考虑有其他东西,一页可以存储16k/14byte=1170个页的地址。同理,第二层就可以存储1170^2=1368900个页的地址。
到了第三层是叶子结点比较特殊。这里分析聚簇索引,包括一整条数据,假设一条数据1k,那么一个页就是16/1=16条数据。
所以第三层的数据有1368900*16=21902400,2千多万条。
如果到了第四层,则可以有1170^3*16=256亿。
但是一般mysql到了第三层就差不多了,只需要通过3次IO,就可以读取到数据所在的叶子结点的页。至于提取需要的记录,则需要在内存中进行一次条件匹配。
这里2kw的原理就是这样的假设前提的。
所以,如果不用BigInt做PK,而改用int的话,则非叶子结点一个数据占(6+4)byte,一页16k/10byte=1638,则第三层可以存储1638^2*16=4.29亿。
如果是个小表,一条数据不够1k,如0.1k,则第三层为2kw*2=2亿,3次IO也是问题。
如果就是1k,256亿条以内的记录,也就是4次IO,真的有想象中的那么不堪吗?不一定!要结合线上的表现来决定要(不要)拆分(256亿有点夸张了,2亿还是很有可能的)。
叶子结点一条记录只有8byte,和聚簇索引不是一个量级的,所以不需要考虑。
所以针对IO的分析,一般都是分析聚簇索引。
这是因为MySQL在32位系统上使用4字节来存储指针,而在64位系统上使用8byte来存储指针。为了在不同系统上保持兼容性,MySQL选择了6byte作为指针的存储长度。
用8byte来保存地址,实属有点浪费,因为6字节可以存储的地址为:32T。如果真的需要这么大的存储空间,估计早就分机器了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。