0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么 MySQL 单表不能超过 2000 万行?

jf_21561199 来源:jf_21561199 作者:jf_21561199 2023-06-29 16:48 次阅读

最近看到一篇《我说 MySQL 每张表最好不要超过 2000 万数据,面试官让我回去等通知》的文章,非常有趣。

文中提到,他朋友在面试的过程中说,自己的工作就是把用户操作信息存到 MySQL 里,因为数据量超大(5000 万条左右),需要每天定时生成 3 张表,然后将数据取模分别存到这三张表里。

接下来是两人的对话:

wKgZomSdRUyAN2pTAAVeDhr6SHQ69.jpeg

面试后续暂且不论,不过,互联网江湖上的确流传着一个说法:单表数据量超过 500 万行时就要进行分表分库,已经超过 2000 万行时 MySQL 的性能就会急剧下降。

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

今天我们就从技术层面剖析一下,MySQL 单表数据不能过大的根本原因是什么?

猜想 1,是索引深度吗?

很多人认为:数据量超过 500 万行或 2000 万行时,引起 B+tree 的高度增加,延长了索引的搜索路径,进而导致了性能下降。事实果真如此吗?

我们先理一下关系,MySQL 采用了索引组织表的形式组织数据,叶子节点存储数据,非叶子节点存储主键与页面号的映射关系。若用户的主键长度是 8 字节时,MySQL 中页面偏移占 4 个字节,在非叶子节点的时候实际上是 8+4=12 个字节,12 个字节表示一个页面的映射关系。

MySQL 默认是 16K 的页面,抛开它的配置 header,大概就是 15K,因此,非叶子节点的索引页面可放 15*1024/12=1280 条数据,按照每行 1K 计算,每个叶子节点可以存 15 条数据。同理,三层就是 15*1280*1280=24576000 条数据。只有数据量达到 24576000 条时,深度才会增加为 4,所以,索引深度没有那么容易增加,详细数据可参考下表:

搜索路径延长导致性能下降的说法,与当时的机械硬盘和内存条件不无关系。

之前机械硬盘的 IOPS 在 100 左右,而现在普遍使用的 SSD 的 IOPS 已经过万,之前的内存最大几十 G,现在服务器内存最大可达到 TB 级。

因此,即使深度增加,以目前的硬件资源,IO 也不会成为限制 MySQL 单表数据量的根本性因素。

那么,限制 MySQL 单表不能过大的根本性因素是什么?

猜想 2,是 SMO 无法并发吗?

我们可以尝试从 MySQL 所采用的存储引擎 InnoDB 本身来探究一下。

大家知道 InnoDB 引擎使用的是索引组织表,它是通过索引来组织数据的,而它采用 B+tree 作为索引的数据结构。B+Tree 操作非原子,所以当一个线程做结构调整(SMO,Struction-Modification-Operation)时一般会涉及多个节点的改动。

SMO 动作过程中,此时若有另一个线程进来可能会访问到错误的 B+Tree 结构,InnoDB 为了解决这个问题采用了乐观锁和悲观锁的并发控制协议。

InnoDB 对于叶子节点的修改操作如下:

方法一,先采用乐观锁的方式尝试进行修改。

对根节点加 S 锁(sharedlock,叫共享锁,也称读锁),依次对非叶子节点加 S 锁。

如果叶子节点的修改不会引起 B+Tree 结构变动,如分裂、合并等操作,那么只需要对叶子节点进行加 X 锁(exclusivelock,叫排他锁,也称为写锁)即可完成修改。如下图中所示:

wKgaomSdRUyAPI3NAAF9WUKhnP8708.png

方式二,采用悲观锁的方式

如果对叶子结点的修改会触发 SMO,那么会采用悲观锁的方式。

采用悲观锁,需要重新遍历 B+Tree,对根节点加全局 SX 锁(SX 锁是行锁),然后从根节点到叶子节点可能修改的节点加 X 锁)。在整个 SMO 过程中,根节点始终持有 SX 锁(SX 锁表示有意向修改这个保护的范围,SX 锁与 SX 锁、X 锁冲突,与 S 锁不冲突),此时其他的 SMO,则需要等待。

wKgZomSdRU2AAa5AAAIz-TsQpIQ935.png

因此,InnoDB 对于简单的主键查询比较快,因为数据都存储在叶子节点中,但对于数据量大且改操作比较多的 TP 型业务,并发会有很严重的瓶颈问题。

在对叶子节点的修改操作中,InnoDB 可以实现较好的 1 与 1、1 与 2 的并发,但是无法解决 2 的并发。因为在方式 2 中,根节点始终持有 SX 锁,必须串行执行,等待上一个 SMO 操作完成。这样在具有大量的 SMO 操作时,InnoDB 的 B+Tree 实现就会出现很严重的性能瓶颈。

解决方案

目前业界有一个更好的方案 B-LinkTree,与 B+Tree 相比,B-LinkTree 优化了 B+Tree 结构调整时的锁粒度,只需要逐层加锁,无需对 root 节点加全局锁,因此,可以做到在 SMO 过程中写操作的并发执行,保持高并发下性能的稳定。

主要改进点有 2 个:

1.中间节点增加 link 指针,指向右兄弟节点;

2.每个节点内增加字段 highkey,存储该节点中最大的 key 值。

新增的 link 指针便是为了解决 SMO 过程中并发写的问题,在 SMO 过程中,B-LinkTree 对修改节点逐层加锁,修改完一层即可放锁,然后去加上一层节点的锁继续修改。这样在 InnoDB 引擎中被 SMO 阻塞的写操作可以有机会再 SMO 操作过程中并发进行。

如下图所示,在节点 2 分裂为节点 2 和 4 的过程中,只需要在最后一步将父节点 1 指向新节点 4 时,对父节点 1 加锁,其他操作均无需对父节点加锁,更无需对 root 节点加锁,因此,大大提升了 SMO 过程中写操作的并发度。

wKgaomSdRU6AWMOeAAE1dXO5hw0004.png

由此可见,和 B+Tree 全局加锁对比起来,B-LinkTree 在高并发操作下的性能是显著优于 B+Tree 的。华为云 GaussDB 当前采用的就是 B-LinkTree 索引数据结构。

InnoDB 的索引组织表更容易触发 SMO

索引组织表的叶子节点,存储主键以及应对行的数据,InnoDB 默认页面为 16K,若每行数据的大小为 1000 字节,每个叶子节点仅能存储 16 行数据。

在索引组织表中,当叶子节点的扇出值过低时,SMO 的触发将更加频繁,进而放大了 SMO 无法并发写的缺陷。

目前业界有一个堆组织表的数据组织方案,也是华为云数据库 GaussDB 采用的方案。它的叶子节点存储索引键以及对应的行指针(所在的页面编号及页内偏移),堆组织表叶子节点可以存更多的数据,分析可得在同样的数据量与业务并发量下,堆组织表会比索引组织表发生 SMO 概率低许多。

性能对比

在 8U32G 的两台服务器分别搭建了 MySQL(B+Tree 和索引组织表)与 GaussDB(B-LinkTree 和堆组织表)的环境,进行了如下性能验证:

实验场景:在基础表的场景上,测试增量随机插入性能。

1.基础表总大小 10G,包含主键随机分布的 1000w 行数据,每行数据 1k;

2.插入主键随机分布的 1000w 行数据,每行数据大小 1k,测试并发插入性能。

结论:随着并发数的上升,GaussDB 能稳步提升系统的 TPS,而 MySQL 并发数的提高并不能带来 TPS 的显著提升。

wKgZomSdRU-AQJMWAAF-DO3U1Ow056.png

总结

MySQL 无法支持大数据量下并发修改的根本原因,是因为其索引并发控制协议的缺陷造成的,而 MySQL 选择索引组织表,又放大了这一缺陷。所以,开源 MySQL 数据库更适用于主键查询为主的简单业务场景,如互联网类应用,对于复杂的商业场景限制比较明显。

相比之下,采用 B-LinkTree 和堆组织表的 GaussDB 数据库在性能和场景应用方面更胜一筹。

审核编辑黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • MySQL
    +关注

    关注

    1

    文章

    801

    浏览量

    26437
  • 华为云
    +关注

    关注

    3

    文章

    2423

    浏览量

    17297
收藏 人收藏

    评论

    相关推荐

    谁说MySQL行数不要超过2000W?

    网上看了一篇文章《为什么说MySQL行数不要超过2000w》,亲自实践了一下,跟原作者有不同的结论。原文的结论是
    的头像 发表于 12-15 10:02 991次阅读
    谁说<b class='flag-5'>MySQL</b><b class='flag-5'>单</b><b class='flag-5'>表</b>行数不要<b class='flag-5'>超过</b><b class='flag-5'>2000</b>W?

    PoE交换机供电的功率为什么不能超过30瓦?

    不能那么高,那么供电功率自然就不能那么高。 由于PoE供电时,网线中既有数据信号又有电力信号,为了不相互影响,也为了保证最佳的供电传输效果,所以行业规定的PoE供电的相关设备的端口供电功率
    发表于 03-17 15:42

    请问PADS原理图库管脚名称是否不能超过40个字?

    pads 原理图库管脚名称不能超过40个字?
    发表于 03-14 07:35

    请问TAS5717的MCLK是12.288MHZ那频率的上下误差最大不能超过多少?

    TAS5717的MCLK如果是12.288MHZ,这个频率的上下误差最大不能超过多少?
    发表于 08-06 10:49

    mysql转列如何操作

    mysql 转列操作
    发表于 04-28 11:27

    800万行代码的鸿蒙系统,在世界上处于什么水平?

    “800万行的代码量,让鸿蒙一跃成为人类有史以来第4大代码量的移动操作系统。要知道当前2.0版本仅包含大屏、手表和车机系统,等到今年12 月手机系统发布后,鸿蒙系统的代码量估计可超过1000万行。而这么庞大的工作量,华为仅用2年
    发表于 09-29 16:04

    【HarmonyOS】800万行代码的鸿蒙系统,在世界上处于什么水平?

    “800万行的代码量,让鸿蒙一跃成为人类有史以来第4大代码量的移动操作系统。要知道当前2.0版本仅包含大屏、手表和车机系统,等到今年12 月手机系统发布后,鸿蒙系统的代码量估计可超过1000万行
    发表于 10-27 10:25

    阿里巴巴推出每秒撰写2万行广告文案的AI新工具

    北京时间7月5日下午消息,中国电子商务巨头阿里巴巴发布一项人工智能工具,可以每秒写入2万行广告文案。
    的头像 发表于 07-07 10:48 3026次阅读

    涛思数据开源TDengine,10多万行C代码,登顶GitHub!

    7月12日,涛思数据宣布将TDengine开源,10多万行C代码,包括最核心的存储引擎和计算引擎都上传到了GitHub上。
    的头像 发表于 07-31 16:07 1.3w次阅读

    一个函数究竟能不能超过50呢?

    有些读者可能看到过类似这样的描述,而自己做项目时,很多函数都比较多(超过50),就会怀疑自己这样写是不是不对?
    的头像 发表于 06-11 12:46 4086次阅读
    一个函数究竟能<b class='flag-5'>不能超过</b>50<b class='flag-5'>行</b>呢?

    MySQL数据最大不要超过多少

    最好不要超过 2000w”,“超过
    的头像 发表于 06-02 15:30 591次阅读
    <b class='flag-5'>MySQL</b><b class='flag-5'>单</b><b class='flag-5'>表</b>数据最大不要<b class='flag-5'>超过</b>多少<b class='flag-5'>行</b>

    MySQL数据最大不要超过多少?为什么?

    想必大家也听说过数据库建议最大2kw 条数据这个说法。如果超过了,性能就会下降得比较厉害。
    的头像 发表于 07-06 09:46 1070次阅读
    <b class='flag-5'>MySQL</b><b class='flag-5'>单</b><b class='flag-5'>表</b>数据最大不要<b class='flag-5'>超过</b>多少<b class='flag-5'>行</b>?为什么?

    再创新高!深开鸿OpenHarmony社区代码贡献量超过200万行

    2023年10月10日,据OpenAtomOpenHarmony(以下简称“OpenHarmony”)官网显示,深开鸿在OpenHarmony社区主仓代码贡献量超过200万行,在华为以外的生态厂商中
    的头像 发表于 10-13 09:54 658次阅读
    再创新高!深开鸿OpenHarmony社区代码贡献量<b class='flag-5'>超过</b>200<b class='flag-5'>万行</b>!

    社区代码贡献企业启新篇,深开鸿代码贡献量超过200万行

    ,社区代码贡献企业取得新成绩,深开鸿成为华为之后,第二家社区代码贡献量超过百万行的生态企业、且总贡献量累计突破200万行,为培育和发展OpenHarmony社区注入源动力!截至目前,华为代码贡献占比
    的头像 发表于 10-18 16:15 691次阅读

    MySQL数据量限制:为何2000万行成为瓶颈?

    很多人认为:数据量超过500万行2000万行时,引起B+tree的高度增加,延长了索引的搜索路径,进而导致了性能下降。事实果真如此吗?
    的头像 发表于 02-27 10:38 5609次阅读
    <b class='flag-5'>MySQL</b><b class='flag-5'>单</b><b class='flag-5'>表</b>数据量限制:为何<b class='flag-5'>2000</b><b class='flag-5'>万行</b>成为瓶颈?