MySQL 单表数据量不要超过2000万,面试官:吹牛!
导读
作为一个合格的 DBA,在遇到线上单表数据量超过千万级别的时候,往往会建议用户通过分表来缩减单表数据量,当用户问为什么单表数据量不能超过千万时,DBA 往往会说:单表数据量超过千万,会影响查询性能。
于是小王以过往项目里的某个 case 为例做了回答:
我负责的项目里涉及到存储用户操作记录的功能,因为每天的数据量比较大,差不多超过 5000 万条,所以我另外又做了分库分表的操作。系统会自动定时生成 3 张表,数据分别存储其中,防止都放在一个表里面导致查询性能降低。
面试官又问:这里为什么要做一个分库分表的操作呢?如果放在同一张表里面,为什么会导致查询性能降低?
小王内心 OS:为什么1+1=2?但他还是语气平常地回答说:
MySQL 单表不要超过 2000 万行基本上是一个行业共识,只有当单表行数超过 500 万行或者单表容量超过 2GB,我们一般才推荐进行分库分表。
01 自增主键角度
02 数据页角度
假设我们有一张 user 表,其中 ID 是自增主键,那么该表在硬盘文件上是 user.ibd(innodb 数据文件,又叫表空间文件)。这个数据文件被划分成很多的数据页,每个数据页大小是16K。
-
一个数据页16K,表的数据量很多,一个数据页可能放不下那么多数据,所以数据被分成好多份,存放在不同的数据页,为了标识具体是哪一个数据页,所以需要有页号来标识;
-
同时为了把这些存放数据的数据页关联起来,又引入了前后指针,用于指向前后的页;
-
数据页需要读写,写入到一半的过程中可能会发生了意外断电等情况,所以为了保证数据页的准确性,还引入了校验码;
-
同时为了在数据页搜索数据提高效率,数据页内部还生成了页目录;
-
除了上述所说的,数据页内剩下的空间就用来存放实际的数据;
数据是以数据页的形式进行存储,数据页和数据页之间是以B+树的形式进行关联,例如:
了解完 B+树是如何存储数据的,我们就可以开始进行数据的估算。
- 对于一个高度为 N 的 B+树,顶层(根节点)有一个非叶子节点,那么第二层就有X个节点,第三层就有 X 的2次方个节点,第四层就有 X 的三次方个节点,以此类推,第 N 层(即叶子节点所在的第 N 层)就有 X 的 N-1 次方个节点;
- 在 B+ 树中,所有的记录都存储在叶子节点中,假设每个叶子节点都可以存储的行记录数为 Y;
- 那么 B+ 树可以存储的数据总量为叶子节点总数乘以每个叶子节点存储的记录数,即:M=(X 的 N-1 次方)乘以 Y;
代入计算:
- 一个数据页大小16K,扣除页号、前后指针、页目录,校验码等信息,实际可以存储数据的大约为15K,假设主键ID为bigint型,那么主键 ID 占用8个 byte,页号占用4个 byte,则 X=15*1024/(8 + 4) 等于1280;
- 一个数据页实际可以存储数据的空间大小,大约为15K,假设一条行记录占用的空间大小为1K,那么一个数据页就可以存储15条行记录,即 Y=15;
- 假设 B+树是两层的:则 N=2,即 M=1280的(2-1)次方 * 15 ≈ 2w ;
- 假设 B+树是三层的:则 N=3,即 M=1280的2次方 * 15 ≈ 2.5 kw;
- 假设 B+树是四层的:则 N=4,即 M=1280的3次方 * 15 ≈ 300亿 ;
综上所述,我们建议单表数据量大小在两千万。当然这个数据是根据每条行记录的大小为 1K 的时候估算而来的,而实际情况中可能并不是这个值,所以这个建议值两千万只是一个建议,而非一个标准。
03 思考
根据 B+树存储数据的计算公式:M = X 的 N-1 次方 * Y:
你,学会(废)了吗
更多精彩 请点击阅读原文
发表评论