MySQL单表数据量为什么不建议超过2000万

626 阅读3分钟

在 MySQL 的性能优化中,一个经常被提及的经验是:

“单表数据量不宜超过 2000 万。”

这并非随意的数字,而是结合了 B+Tree 索引结构、单行数据大小、页结构与缓存命中率 等多个因素所形成的经验总结。

本篇将从索引结构出发,深入解析单表数据量、索引层数、每行数据大小三者之间的关系,帮助你科学判断:你的表还能承受多大的数据量?

一、MySQL 中索引的本质是什么?

MySQL(InnoDB 引擎)使用 B+Tree 作为主键索引和辅助索引的底层结构。

  • 每一个 叶子节点 是一个 数据页,默认大小是 16KB;
  • 索引结构就是一棵 多路平衡查找树
  • 每一层 B+Tree 索引页存储多个 key → 形成“树的高度”;
  • 树越高,查询路径越长,IO 越多,性能越差。

二、单行数据大小对索引结构的影响

一个数据页(16KB)中能容纳多少条记录,取决于每条记录占用的字节数。

示例:假设行大小不同,数据页能容纳的记录数

每行数据大小每页记录数(大致)
100B160 行左右
500B32 行左右
1000B16 行左右
2000B8 行左右

每页不能被完全填满,还包括页目录、槽位、指针等元数据开销。 实际上数据页大约有 15KB 空间可以存放数据,假如 一条数据占用 1K,那么一个数据页最大也就存放 15 条数据

三、非叶子节点个数估算

非叶子节点的数据页也是 16KB,除去数据页的结构信息占用 1K,大约有 15K 可以存储数据,非叶子节点不存储数据,只存储主键信息和页号 假如数据表主键是 bigint类型,占用 8byte空间,页号占用 4byte,那么一条数据是12byte数据,那么一个非叶子节点的数据是:

 15KB * 1024 / 12 = 1280

四、索引树高度的估算方法

设:

  • D = 每个非叶子页能容纳的指针个数(子节点个数);
  • L = 树的层数;
  • N = 总数据条数;
  • 则理论上:
    N≤D(L−1)×R 其中 R 为每页记录数。

例如:若每页可容纳 15 条记录,非叶子节点每页能容纳 1280 个主键数据(key),那 3 层 B+Tree 可容纳约 1280 × 1280 × 100 = 2,500 万条记录。

五、结合数据大小估算不同层数可支持的数据量

假设配置:

  • 数据页大小:16KB,其中只有 15K 空间存放数据(除去页目录、槽位等)
  • 索引页:每个节点约容纳 1280 个指针(非叶子页)
  • 数据页:每行数据分别为 100B、500B、1KB、2KB
每行大小每页记录数3 层 B+Tree 可支持数据量
100B1601280 × 1280 × 150 ≈ 24576 万行
500B321280 × 1280 × 30 ≈ 4915 万行
1KB161280 × 1280 × 15 ≈ 2458 万行
2KB81280 × 1280 × 8 ≈ 1311 万行

实际上,假如一条数据有 1KB 大小,三层 B+Tree可以存放的数据大约是 2458 万行。2000W 只是一个推荐值。 在设计表的时候,可以通过纵向拆表,减少单条数据的占用空间来增大单表的存储量,如上表格中,如果单条数据只有 100Byte,单表可以存放 2.45 亿数据,查询性能也不会太差

索引结构示例:

mysql 索引结构.drawio.png