MySQL 单表可以放多少数据,最多 2000 万?
ztj100 2025-05-27 19:14 9 浏览 0 评论
关于单表能存多少数据,阿里 JAVA 开发手册提出,建议最大 2000 万。
然后也看过一篇文章,可以往单表塞 1 亿。
当然,以上其实都有一些理论支撑,但是都不全面,也没有结合具体实际的场景。
这篇文章,结合之前学习的知识,进行一个整体汇总,并贴合实际场景展开。
01 理论知识
B+ 树
MySQL 的底层结构用 B+ 树存储,这个估计地球人都知道。
为了便于后续讲解,先普及几个概念:
- 对于非聚集索引,B+ 树的叶子节点和非叶子节点存储的都是索引指针;
- 对于聚集索引,B+ 树的非叶子节点存储的是索引指针,叶子节点存储的是数据,顺序排列;
- InnoDB 中的 B+ 树的高度一般会保持在 3 层以内,我们就以 3 层来定。
下图是聚集索引,3 层 B+ 树的结构:
虚线部分,可以找到对应页码的数据,这里很基础,不去过多解读。
页存储
B+ 树节点的存储结构是 “页”,一页的大小 16 KB。
下面是页结构示意图:
再看看对页结构的解读:
那一页能留多少存储空间呢?
除了 User Records 和 Free Space 以外所占用的存储是 38 + 56 + 26 + 8 = 128。
当新记录插入到 InnoDB 聚集索引中时,InnoDB 会尝试留出 1/16 的页面空闲以供将来插入和更新索引记录,所以就只剩下 15/16。
可存储空间 = 15/16 * 1024 - 128 = 15232 字节。
行存储
MySQL 的数据是行存储,MySQL 5.6 默认行格式为 COMPACT(紧凑),5.7 及以后的默认行为 DYNAMIC(动态)。
下面是行结构示意图:
再看看对行结构的解读:
02 叶子节点计算
3 层 B+ 树最大数据量
前面说了,我们的 B+ 树是 3 层,第一层就一个根节点,能存放 X 个指针。
第二层的每个节点,也能存放 X 个指针,指向第三层 X 个节点。
第三层的每个节点,存放 Y 个数据。
3 层 B+ 树最大数据量 = x ^ 2 * y。
叶子节点总数 x ^ 2 计算
我们先看一页能存储多少个指针索引。
每一条索引记录当中都包含了当前索引的值 、一个 6 字节的指针信息 、一个 5 字节的行标头,用来指向下一层数据页的指针。
索引记录当中的指针占用空间我没在官方文档里找到,这个 6 字节是我参考其他博文,他们说源码里写的是 6 字节。
假设我们的主键 id 为 bigint 型,也就是 8 字节。
索引指针大小:8 + 6 + 5 = 19 字节。
前面已经算出,每页可存储空间 15232 字节。
单页可存储索引指针:15232 / 19 ≈ 801 条。
那算上页目录的话,按每个槽平均 6 条数据计算的话,至少有 801 / 6 ≈ 134 个槽,需要占用 268 字节的空间。
把存数据的空间分一点给槽的话,我算出来大约可以存 787 条索引数据。
单页数据存储索引指针:
- 最终单页可存储 bigint 型索引指针:(15232 - 268)/ 19 ≈ 787 条;
- 最终单页可存储 int 型索引指针 993 条。
叶子节点总数:
- 主键为 bigint 的表可以存放 787 ^ 2 = 619369 个叶子节点;
- 主键为 int 的表可以存放 993 ^ 2 = 986049 个叶子节点。
说明:以上的数据计算,仅供参考,因为有的文章说,在主键为 bigint 的情况下,可存放 160 万叶子节点,整整多出 65 万。
03 总记录数计算
溢出页
前面提到过,MySQL 行存储格式包括 COMPACT 和 DYNAMIC,我们这里只看 DYNAMIC。
DYNAMIC 怎么理解?
在一行数据中,当某列太长时,叶子节点无需将该数据直接存储 ,而是存储指向该数据的指针,真实数据全部存储在溢出页。
使用 DYNAMIC 格式,较短的列会尽可能保留在 B+ 树节点中,从而最大限度地减少给定行所需的溢出页数。
那 COMPACT 呢?
COMPACT 行格式则是将前 768 个字节和 20 字节的指针存储在 B+ 树节点的记录中,其余部分存储在溢出页上。
这里我们只讨论 DYNAMIC 情况。
最少总记录数
前面我们提到,最大行长度略小于数据库页面的一半,之所以是略小于一半,是由于每个页面还留了点空间给页格式的其他内容,所以我们可以认为每个页面最少能放两条数据,每条数据略小于 8 KB。
如果某行的数据长度超过这个值,那 InnoDB 肯定会分一些数据到 溢出页当中去了,所以我们不考虑。
那每条数据 8 KB 的话,每个叶子节点就只能存放 2 条数据。
在主键为 int 的情况下,最少总记录数:2 × 986049 ≈ 124 万。
最多总记录数
假设我们的表是这样的:
CREATE TABLE `course_schedule` (
`id` int NOT NULL,
`teacher_id` int NOT NULL,
`course_id` int NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
先来分析一下这张表的行数据:无 null 值列表,无可变长字段列表,需要算上事务 ID 和指针字段,需要算上行记录头。
每行数据占用空间:4 + 4 + 4 + 6 + 7 + 5 = 30。
每个叶子节点存放:15232 ÷ 30 ≈ 507。
算上页目录槽位所占空间,每个叶子节点可存放 502 条。
在主键为 int 的情况下,最多总记录数:502 × 986049 ≈ 5 亿。
04 实际场景
上面的场景是两个极端, 我们看一个具体的示例。
CREATE TABLE `blog` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '博客id',
`author_id` bigint unsigned NOT NULL COMMENT '作者id',
`title` varchar(50) CHARACTER SET utf8mb4 NOT NULL COMMENT '标题',
`description` varchar(250) CHARACTER SET utf8mb4 NOT NULL COMMENT '描述',
`school_code` bigint unsigned DEFAULT NULL COMMENT '院校代码',
`cover_image` char(32) DEFAULT NULL COMMENT '封面图',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`release_time` datetime DEFAULT NULL COMMENT '首次发表时间',
`modified_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`status` tinyint unsigned NOT NULL COMMENT '发表状态',
`is_delete` tinyint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `author_id` (`author_id`),
KEY `school_code` (`school_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_mysql500_ci ROW_FORMAT=DYNAMIC;
分析一下这张表的行记录:
- 行记录头信息:肯定得有,占用 5 字节;
- 可变长度字段列表:表中 title 占用 1 字节,description 占用 2 字节,共 3 字节;
- null 值列表:表中仅 school_code、cover_image、release_time 3 个字段可为 null,故仅占用 1 字节;
- 事务 ID 和指针字段:两个都得有,占用 13 字节。
再看看字段内容信息:
- id、author_id、school_code 均为 bigint 型,各占用 8 字节,共 24 字节;
- create_time、release_time、modified_time 均为 datetime 类型,各占 8 字节,共 24 字节;
- status、is_delete 为 tinyint 类型,各占用 1 字节,共 2 字节;
- cover_image 为char(32),字符编码为表默认值 utf8,占用 32 字节;
- title、description 分别为 varchar(50)、varchar(250),这两个应该都不会产生溢出页(不太确定),字符编码均为 utf8mb4,实际生产中 70% 以上都是存的中文( 3 字节),25% 为英文(1 字节),还有 5% 为 4 字节的表情,则存满的情况下将占用 (50+250)×(0.7×3+0.25×1+0.05×4) = 765 字节。
统计上面的所有分析,共占用 869 字节,则每个叶子节点可以存放 15232 ÷ 869 ≈ 17 条,算上页目录,仍然能放 17 条。
主键为 bigint,最大总记录数:17× 619369=10,529,273 ≈ 1053 万。
相关推荐
- Spring IoC Container 原理解析
-
IoC、DI基础概念关于IoC和DI大家都不陌生,我们直接上martinfowler的原文,里面已经有DI的例子和spring的使用示例...
- SQL注入:程序员亲手打开的潘多拉魔盒,如何彻底封印它?
-
一、现象:当你的数据库开始"说话",灾难就来了场景还原:...
- Java核心知识3:异常机制详解
-
1什么是异常异常是指程序在运行过程中发生的,由于外部问题导致的运行异常事件,如:文件找不到、网络连接失败、空指针、非法参数等。异常是一个事件,它发生在程序运行期间,且中断程序的运行。...
- MyBatis常用工具类三-使用SqlRunner操作数据库
-
MyBatis中提供了一个非常实用的、用于操作数据库的SqlRunner工具类,该类对JDBC做了很好的封装,结合SQL工具类,能够很方便地通过Java代码执行SQL语句并检索SQL执行结果。SqlR...
- 爆肝2W字梳理50道计算机网络必问面试题
-
1.说说HTTP常用的状态码及其含义?思路:这道面试题主要考察候选人,是否掌握HTTP状态码这个基础知识点。...
- SpringBoot整合Vue3实现发送邮箱验证码功能
-
1.效果演示2.思维导图...
- 最全JAVA面试题及答案(200+)
-
Java基础1.JDK和JRE有什么区别?JDK:JavaDevelopmentKit的简称,Java开发工具包,提供了Java的开发环境和运行环境。JRE:JavaRunti...
- Java程序员找工作翻车现场!你的项目描述踩了这几个坑?
-
Java程序员找工作翻车现场!你的项目描述踩了这几个坑?噼里啪啦敲了三年代码,简历一投石沉大海?兄弟,问题可能出在项目描述上!知道为什么面试官看你的项目像看天书吗?因为你写了三个致命雷区:第一,把项目...
- 2020最新整理JAVA面试题附答案,包含19个模块共208道面试题
-
包含的模块:本文分为十九个模块,分别是:Java基础、容器、多线程、反射、对象拷贝、JavaWeb、异常、网络、设计模式、Spring/SpringMVC、SpringBoot/Spring...
- 底层原理深度解析:equals() 与 == 的 JVM 级运作机制
-
作为Java开发者,你是否曾在集合操作时遇到过对象比较的诡异问题?是否在使用HashMap时发现对象丢失?这些问题往往源于对equals()和==的误解,以及实体类中这两个方法的不当实...
- 雪花算法,什么情况下发生 ID 冲突?
-
分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的...
- 50个Java编程技巧,免费送给大家
-
一、语法类技巧1.1.使用三元表达式普通:...
- 如何规划一个合理的JAVA项目工程结构
-
由于阿里Java开发手册对于工程结构的描述仅限于1、2节简单的概述,不能满足多样的实际需求,本文根据多个项目中工程的实践,分享一种较为合理实用的工程结构。工程结构的原则有依据、实用。有依据的含义是指做...
- Java 编程技巧之单元测试用例编写流程
-
温馨提示:本文较长,同学们可收藏后再看:)前言...
- MyBatis核心源码解读:SQL执行流程的奇妙之旅
-
MyBatis核心源码解读:SQL执行流程的奇妙之旅大家好呀!今天咱们要来一场既烧脑又有趣的旅程——探索MyBatis这个强大框架的核心秘密。你知道吗?当你在项目里轻轻松松写一句“select*f...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)