我说MySQL每张表最好不超过2000万条数据,面试官让我回去等通知?
事情是这样的
下面是我朋友的面试记录:
面试官:讲一下你实习做了什么。
朋友:我在实习期间做了一个存储用户操作记录的功能,主要是从MQ获取上游服务发送过来的用户操作信息,然后把这些信息存到MySQL里面,提供给数仓的同事使用。由于数据量比较大,每天大概有四五千多万条,所以我还给它做了分表的操作。每天定时生成3张表,然后将数据取模分别存到这三张表里,防止表内数据过多导致查询速度降低。
这表述,好像没什么问题是吧,别急,接着看:
面试官:那你为什么要分三张表呢,两张表不行吗?四张表不行吗?
朋友:因为MySQL每张表最好不超过2000万条数据,否则会导致查询速度降低,影响性能。我们每天的数据大概是在五千万条左右,所以分成三张表比较稳妥。
面试官:还有吗?
朋友:没有了……你干嘛,哎呦~
面试官:那你先回去等通知吧。
🤣🤣🤣讲完了,看出什么了吗,你们觉得我这位朋友回答的有什么问题吗?
前言
很多人说,MySQL每张表最好不要超过2000万条数据,否则就会导致性能下降。阿里的Java开发手册上也提出:单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。
但实际上,这个2000万或者500万都只是一个大概的数字,并不适用于所有场景,如果盲目的以为表数据只要不超过2000万条就没问题了,很可能会导致系统的性能大幅下降。
实际情况下,每张表由于自身的字段不同、字段所占用的空间不同等原因,它们在最佳性能下可以存放的数据量也就不同。
那么,该如何计算出每张表适合的数据量呢?别急,慢慢往下看。
本文适合的读者
阅读本文你需要有一定的MySQL基础,最好对InnoDB和B+树都有一定的了解,可能需要有一年以上的MySQL学习经验(大概一年?),知道 “InnoDB中B+树的高度一般保持在三层以内会比较好” 这条理论知识。
本文主要是针对 “InnoDB中高度为3的B+树最多可以存多少数据” 这一话题进行讲解的。且本文对数据的计算比较严格(至少比网上95%以上的相关博文都要严格),如果你比较在意这些细节并且目前不太清楚的话,请继续往下阅读。
阅读本文你大概需要花费10-20分钟的时间,如果你在阅读的过程中对数据进行验算的话,可能要花费30分钟左右。
本文思维导图
图片
InnoDB三层B+数的存储计算-思维导图
基础知识快速回顾
众所周知,MySQL中InnoDB的存储结构是B+树,B+树大家都熟悉吧?特性大概有以下几点,一起快速回顾一下吧!
*注:下面这这些内容都是精华,看不懂或者不理解的同学建议先收藏本文,之后有知识基础了再回来看 。*🤣🤣
聚簇索引的叶子节点存的是这条数据的所有字段信息。所以我们 select * from table where id = 1 的时候,都是要去叶子节点拿数据的。
非聚簇索引的叶子节点存的是这条数据所对应的主键和索引列信息。比如这条非聚簇索引是username,然后表的主键是id,那该非聚簇索引的叶子节点存的就是 username 和 id,而不存其他字段。相当于是先从非聚簇索引查到主键的值,再根据主键索引去查数据内容,一般情况下要查两次(除非索引覆盖),这也称之为*回表*,就有点类似于存了个指针,指向了数据存放的真实地址。
MySQL5.7文档的解释是:
图片
文档地址:https://dev.mysql.com/doc/refman/5.7/en/innodb-file-space.html
-
对于 4KB、8KB、16KB 和 32KB设置 ,最大行长度略小于数据库页面的一半 ,例如:对于默认的 16KB页大小,最大行长度略小于 8KB 。
而对于 64KB 页面,最大行则长度略小于 16KB。
如果行超过最大行长度, 则将可变长度列用外部页存储,直到该行符合最大行长度限制。就是说把varchar、text这种长度可变的存到外部页中,来减小这一行的数据长度。