欢迎光临散文网 会员登陆 & 注册

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

2023-06-28 21:58 作者:消费测评世界  | 我要投稿

【深度分析】为什么MySQL表单不能过大?

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

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

接下来是两人的对话


面试后续暂且不论,不过,互联网江湖上的确流传着一个说法:单表数据量超过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所以,索引深度没有那么容易增加,详细数据可参考下表:

索引深度

最大数据量(行数)

1

15

2

19200(15*1280)

3

24576000(15*1280*1280)

4

31457280000 (15*1280*1280*1280)

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

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

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

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

猜想2,是SMO无法并发

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

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

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

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

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

对根节点加S锁shared lock,叫共享锁称读锁,依次对非叶节点加S锁

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


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

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

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


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

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

解决方案

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

主要改进点有2个

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

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

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

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


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

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

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

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

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

性能对比

在8U32G的两台服务器分别搭建了MySQLB+Tree和索引组织表GaussDBB-Link Tree和堆组织的环境,进行了如下性能验证:

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

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

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

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


总结

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

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

2023-6-d

华为保密信息,未经授权禁止扩散

9, 9

为什么MySQL单表不能超过2000万行?的评论 (共 条)

分享到微博请遵守国家法律