MySQL 单表可以放多少数据,最多 2000 万?

Mysql——单表最多数据量多少需要分表 MySQL单表分表标准及B+树存储容量分析 阿里开发公约建议单表超过500万行或2GB时考虑分表。B+树的存储能力取决于页大小和行数据量,默认16KB的页可存储约16184字节有效数据。以一个包含5列的表为例,每行约100字节,单页可存161条记录。三层B+树理论上可存储约4.2亿条记录(100字节/行)。实际存储量会随行大小变化,如1KB/行时约4000万条。因此,单纯以行数判断是否分表并不准确,需结合数据容量综合评估。 阅读详情
AI摘要

文章详细探讨了MySQL中单表数据存储的理论限制,如B+树结构、行和叶节点设计,以及DYNAMIC格式对数据存储的影响。通过实例计算得出在不同场景下的最大和最少记录数,强调理论知识的学习价值但提醒不要直接照搬数值。

关于单表能存多少数据,阿里 JAVA 开发手册提出,建议最大 2000 万。

然后也看过一篇文章,可以往单表塞 1 亿。

当然,以上其实都有一些理论支撑,但是都不全面,也没有结合具体实际的场景。

这篇文章,结合之前学习的知识,进行一个整体汇总,并贴合实际场景展开。

上文章目录。

01 理论知识

B+ 树

MySQL 的底层结构用 B+ 树存储,这个估计地球人都知道。

为了便于后续讲解,先普及几个概念:

  • 对于非聚集索引,B+ 树的叶子节点和非叶子节点存储的都是索引指针;

  • 对于聚集索引,B+ 树的非叶子节点存储的是索引指针,叶子节点存储的是数据,顺序排列;

  • InnoDB 中的 B+ 树的高度一般会保持在 3 层以内,我们就以 3 层来定。

下图是聚集索引,3 层 B+ 树的结构:

虚线部分,可以找到对应页码的数据,这里很基础,不去过多解读。

页存储

B+ 树节点的存储结构是 “页”,一页的大小 16 KB。

下面是页结构示意图:

再看看对页结构的解读:

名称空间含义和作用等
File Header38字节文件头:包括校验页号、前后节点的两个指针、页类型、表空间等。
Page Header56字节页头:用来记录页的状态信息,包括页目录的槽数、空闲空间的地址等。
Infimum & supremum26字节用来限定当前页记录的边界值,包含一个最小值和一个最大值。
User Records不固定用户记录,我们插入的数据就存储在这里。
Free Space不固定空闲空间,用户记录增加的时候从这里取空间。
Page Directort不固定页目录,用来存储页当中用户数据的位置信息。
File Trailer8字节文件结尾信息,校验页面完整性。

那一页能留多少存储空间呢?

除了 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(动态)。

下面是行结构示意图:

图片

再看看对行结构的解读:

名称空间含义和作用等
行记录头信息5字节包含标志位、数据类型等。
可变长度字段列表不固定保存可变长度的字段占用字节数,比如 varchar、text、blob等。
null值列表不固定存储可以为 null 的字段,每个可为 null 的字段在这里占用一个 bit。
事务ID和指针字段6+7字节包含了一个6字节的事务ID和一个7字节的回滚指针。
实际数据不固定真实存储数据。

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 万。

05 后记

对于上述知识,其实主要是整理小白 Debug 和掘金阿杆的两篇博文。

文章的很多图片是选取「小白 Debug」的博文,数值计算和案例,是选取的「掘金阿杆」的博文。

重新整理后,整体可读性更强,数字依据更考究。

该文的理论知识,以及整体计算的逻辑和思想,是可以学习接借鉴的,但是对于里面很多数值的精确度,其实我是有些质疑的,比如主键为 int 的表可以 986049 个叶子节点,个人感觉还是少了。

无论如何,这两篇文章应该是我最近看到的,关于 Mysql 存放数据大小计算的最好的两篇,不建议照搬里面的数据,但本文的理论知识、计算思路是完全可以学习和借鉴的。

最后附上参考的两篇博文:

掘金阿杆:https://juejin.cn/post/7165689453124517896
小白 Debug:https://mp.weixin.qq.com/s/AOtXJNmt50KowkSDN-FlhA
你的mysql到底能存多少数据呢? mysql存储多少数据 阅读详情

相关推荐

为什么MySQL单表数据在2000W+后会明显下降

事实上,这个传闻据说最早起源于百度。具体情况大概是这样的,当年的 DBA 测试 MySQL性能时发现,当单表的量在 2000 万行量级的时候,SQL 操作的性能急剧下降,因此,结论由此而来。对此,有阿里的黄金铁律支撑,所以,很多人设计大数据存储时,多会以此为标准,进行分表操作。有业界传说和阿里巴巴的开发手册支撑,这个结论应该是靠谱的,毕竟实践出真知,但这背后的原理是什么呢,目前我们用的MYSQL大部分都是InnoDB引擎,现在我们就从InnoDB引擎说起来扒一扒为什么单表数据在2000W+后会明显下降。

程序员野蛮成长 1041

MySQL十四:单表最大2000W行数据

在互联网技术圈中有一个说法:MySQL 单表数据量大于 2000 W行,性能会明显下降。网传这个说法最早由百度传出,真假不得而知。但是却成为了行业内一个默认的标准。

Edwin_Hu的博客 1万+

【MySQL】阿里:MySQL 单表数据最大不要超过多少行?为什么?

B+树叶子和非叶子结点的数据页都是16k,且数据结构一致,区别在于叶子节点放的是真实的行数据,而非叶子结点放的是主键和下一个页的地址。B+树一般有两到三层,由于其高扇出,三层就能支持2kw以上的数据,且一次查询最多1~3次磁盘IO,性能也还行。存储同样量级的数据,B树比B+树层级更高,因此磁盘IO也更多,所以B+树更适合成为mysql索引。索引结构不会影响单表最大行数,2kw也只是推荐值,超过了这个值可能会导致B+树层级更高,影响查询性能。单表最大值还受主键大小和磁盘大小限制。

九师兄 3631

MySQL学习笔记-2

悲观锁(数据库):认为数据随时会被修改,因此每次读取数据之前都会上锁,防止其它事务读取或修改数据;应用于数据更新比较频繁的场景;乐观锁:操作数据时不会上锁,但是更新时会判断在此期间有没有别的事务更新这个数据,若被更新过,则失败重试;适用于读多写少的场景。乐观锁的实现方式有:不采用数据库自身的锁机制,而是通过程序来实现。加一个版本号或者时间戳字段,每次数据更新时同时更新这个字段;先读取想要更新的字段或者所有字段,更新的时候比较一下,只有字段没有变化才进行更新。

yueliangzy的博客 4761

《遥感大模型生产级实战:从数据到决策的端到端AI工程》系列第三部分:城市洪涝灾害应急响应与评估平台实战-文章 14:项目二启动与多源异构数据对齐

我们将系统性地梳理城市洪涝场景下的所有关键数据源,从天上的卫星(光学与SAR)、空中的无人机,到地面的物联网传感器和社交媒体信息流,深入剖析每种数据在洪涝响应中的独特价值、获取方式与内在局限性。本章的核心将是一个详尽的、生产级的数据对齐技术全景,我们将分步解决三大核心对齐难题:空间对齐(将所有数据投影到统一的地理坐标系)、时间对齐(处理不同采样频率的时间序列)以及最困难的语义对齐(将文本描述与物理观测相关联)。

panshengwu的博客 2003

螺丝锁付系统软件设计 C# Winform

视觉螺丝锁付系统软件设计 C# Winform ,这是其中通信子模块设计

weixin_42522973的博客 340

MySQL单表数据不超过多少好?

若单表数据量远大于缓冲池(如 100GB 表 + 8GB 内存),频繁的磁盘换入换出会导致性能骤降。:缓冲池(Buffer Pool)可缓存整个表的热点数据(如512GB内存缓存100GB的表)。单表超过 1000万行后,索引维护成本(B+树分裂、锁竞争)显著增加,TPS 下降。:3层B+树时,范围查询或非主键索引可能需要更多磁盘I/O,性能开始下降。:相比传统机械硬盘,随机I/O性能提升百倍,极大缓解大数据量下的磁盘瓶颈。:如电商商品表,通过缓存(Redis)拦截99%的查询,数据库压力极小。

weixin_41464496的博客 3846

分布式定时任务(XXL-JOB)整合达梦数据库 带源码

背景 1. 因公司需要可视化管理配置调度任务,查询项目选择XXL-JOB,它是开源项目,入手很简单,详情可以参考官方文档; 2. 因项目的机密性,选择数据库为国内知名的达梦数据库7,与Java项目的整合详情可以参考SpringBoot 集成 达梦数据库 maven依赖本地jar包; 3. 因XXL-JOB暂时没有找到集成达梦数据库的案例,博主自己整合DM7踩过很多的坑,特此整合一个简单可直接...

艾斯-李的博客 3814

为什么MySQL单表不要超过2000万行数据?

本文深入分析了MySQL单表数据量不超过2000万行的行业共识。其理论源于B+树三层索引结构约2457万行的容量限制,但更关键的是高并发下的结构修改操作(SMO)性能瓶颈。测试显示,传统MySQL在高并发写入时扩展性受限。尽管现代硬件缓解了索引深度问题,2000万仍作为合理参考值,需结合业务场景考量。文章提出了分库分表、冷热分离等优化策略,并指出新一代分布式数据库是突破限制的方向。这一数字背后的原理比机械遵守更重要,开发者应理解底层机制,根据业务需求设计合适的存储方案。

m0_66884848的博客 1200

华为AC外置Portal认证方案配置步骤指南

华为AC外置Portal认证方案配置步骤指南

m0_46129105的博客 7663

记录:MCGS和正弦变频器通讯

触摸屏实现对变频器:启动、停止、频率设定、频率读取、电压读取、电流读取。通讯方式Modbus RTU。

m0_61837027的博客 1026

面试官:MYSQL单表数据达2000万性能严重下降,为什么

原文:https://zhuanlan.zhihu.com/p/355302417 不知从什么时候开始,有着MySQL单表数据量超过2000万性能急剧下降的说法。 在中国互联网技术圈流传着这么一个说法:MySQL 单表数据量大于 2000 万行,性能会明显下降。事实上,这个传闻据说最早起源于百度。具体情况大概是这样的,当年的 DBA 测试 MySQL性能时发现,当单表的量在 2000 万行量级的时候,SQL 操作的性能急剧下降,因此,结论由此而来。然后又据说百度的工程师流动到业界的其它公司,随之也带去了这个

kwinH的博客 3023

C#程序突然崩溃怎么办?5分钟学会分析Dump文件(Visual Studio 2022实战)

本文详细介绍了在C#程序崩溃或无响应时,如何捕获并分析Dump文件以快速定位问题。通过Visual Studio 2022实战演示,重点讲解了配置符号服务器、解读调用堆栈与内存状态,以及针对CPU飙高、内存泄漏等典型场景的分析方法,帮助开发者高效进行故障诊断。

docker8compose的博客 474

MySQL单表数据量超过2000万性能急剧下降的说法靠谱?

原文:https://dwz.cn/DpVUL65R今天,探讨一个有趣的话题:MySQL 单表数据达到多少时才需要考虑分库分表?有人说 2000 万行,也有人说 500 万行。那么,你觉...

公众号-老炮说Java 1976

显著性算法 + 伪彩变换

利用opencv得到显著图和伪彩图

正在挣扎中的人 2298

(3dnr)多帧视频图像去噪 (一)

视频图像去噪主要利用相邻帧间内容相似性,通过时域帧平均降低随机噪声。为避免运动物体产生"拖尾"现象,可采用运动自适应或运动补偿时域滤波方法。前者根据运动强度动态调整滤波系数,后者通过运动补偿使参考帧更接近当前帧。运动补偿方法虽能更好处理运动区域,但计算复杂度高且对快速运动场景效果有限。相比之下,运动自适应方法在实时视频处理中更具优势,能平衡去噪效果与硬件资源消耗。两种方法可根据场景动态切换以获得最佳去噪效果。

大熊 1867

MySQL一张表最多能存多少数据?

MySQL一张表中可以存放多少数据? 一个简单的测试 private static void insertDataDemo() { DButil dButil = new DButil(); myCon = dButil.getConnection(); try { int i = 0; while(1==1) { i++; String sql = "in...

promote的博客 2万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

为什么 MySQL 单表不建议超过 2000 万?一文讲透底层原理

本文深入解析了MySQL单表数据量的合理上限问题,指出"2000万条"的经验法则源于InnoDB引擎的存储机制和B+树索引结构特性。通过分析数据页(16KB)的存储结构和B+树三层架构,揭示了保持查询性能的关键在于控制磁盘IO次数:三层B+树约支持2500万条记录(假设单行1KB),超过则需四次IO访问。文章强调实际容量与单行数据大小密切相关(如250B/行可达1亿条),并对比了B+树相比B树的性能优势,最后提出优化建议包括控制单表数据量、优化行大小、冷热分离和分库分表等策略。

qq_46371374的博客 1575

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

MySQL单表2000万数据查询慢解决方案推荐

MySQL单表2000万数据查询慢解决方案推荐 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代数据驱动的应用中,MySQL作为最常用的关系型数据库之一,其性能优化一直是开发者和数据库管理员关注的焦点。随着数据量的不断增长,单表数据量达到2000万时,查询性能可能会显著下降,导致系统响应时间变慢,用户体验受损。为了解决这一问题,我们推出了“MySQL单表2000万...

gitblog_06686的博客 1018

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

阿里规范说MySQL单表行数不要超过2000w,为啥?

Mysql 的表数据是以页的形式存放的,页在磁盘中不一定是连续的。页的空间是 16K, 并不是所有的空间都是用来存放数据的,会有一些固定的信息,如,页头,页尾,页码,校验码等等。在 B+ 树中,叶子节点和非叶子节点的数据结构是一样的,区别在于,叶子节点存放的是实际的行数据,而非叶子节点存放的是主键和页号。索引结构不会影响单表最大行数,2kw 也只是推荐值,超过了这个值可能会导致 B + 树层级更高,影响查询性能。...

LoveSummer 1万+

数据库性能优化—MySQL单表最大记录数超过多少时性能会严重下降

以前没有想过MySQL数据库的单表最大行数,直到最近interview时被问到c语言中int类型的最大值是多少时才想到Mysql单表最大行数的问题。 一开始被问到C语言中int类型的最大值有点懵逼,一般这种问题都是在校招时候会被问到,对于工作多年的人不会问这个问题。被问到这个问题的时候,大脑中思考的不是int类型最大值到底是多少?而是为什么这个问题很经典,经常被问,了解这个东西能用到什么地方呢?于是很快想到了MySql单表的最大记录数是多少,因为表的id一般是自增长的int类型。 下面是粘贴自其他伙伴的

sanmi8276的博客 1万+

MySQL单表2000万行限制技术报告

监控预警当表体积接近20GB(按1KB/行估算)时启动优化容量规划:graph LRA[单表预估数据量] -->|≤2000万| B[单表存储]A -->|>2000万| C[分库分表/分区]性能验证执行EXPLAIN观察查询是否触发Temporary监控确认物理I/O量💡终极方案数据量超亿级时,迁移至分布式数据库(TiDB/PolarDB)或OLAP系统(ClickHouse)附:三层B+树容量计算器。

it_manman的博客 971

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

在 MySQL 的性能优化中,一个经常被提及的经验是:“单表数据量不宜超过 2000 万。这并非随意的数字,而是结合了等多个因素所形成的经验总结。

2401_89221445的博客 975
上一篇: Hutool 嘎嘎香,开炫了!
下一篇: MySQL索引全解:从理论到实践,打造高效查询的指南
Java_2017_csdn
博客等级 码龄10年 329粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值