看到使用分库分表来解决性能问题的时候心里总是不能太理解。
如果同事发生大量请求的时候,损害性能的是硬盘的随机读。那么分库分表也没有对性能的瓶颈进行“分治”啊。
应该的做法是使用一块新的硬盘来创建分库。但是基本的文章都没有提到这点。而且基本上也不会有公司这么做,毕竟现在一快硬盘在1T所有,一个数据库肯定占用不了这么多地方。而且程序员在申请数据库的时候,也没有办法说明使用不同的硬盘来部署这数据库。而且也不知道部署在这些硬盘上有没有大量的随机读。
还有好多人都觉得MYSQL数据库有性能问题,在单表超过500W或者2000W的时候就要分库分表。我觉得从MYSQL的数据结构来说,应该不存在这些问题。(好多帖子说是避免树高过高。)其实树高增加一层会增加一个数量级的数据存放量。如果通过分库分表来减少树高,可以累死程序员。这也不是程序员应该考虑的。MYSQL只要缓存一个顶级节点pageCache就相当于做了“分库分表”了。所以一直认为分库分表是个伪命题。
下面使用程序来做一下实验来证明自己的想法。
在测试环境Linux系统下安装mysql 5.7.41。本地使用java 8 为客户端代码。
实验一:单表操作
1)创建数据库test
2)创建T_PERSON表
3)使用Java JDBC 批量插入100,000,000条数据,4096为一个批次。总共耗时为:2150秒。
实验二:分表不分库
- 创建数据库T_PERSON_1, T_PERSON_2, T_PERSON_3, T_PERSON_4, T_PERSON_5, T_PERSON_6, T_PERSON_7, T_PERSON_8.
- 使用java JDBC批量插入100,000,000条数据,4096*8为一个批次。每张表总共12,500,000条数据(小于2000W条)。总共耗时为:2015秒。
实验三:分库分表
- 创建数据库Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8
- 每个库创建T_PERSON表
- 使用java JDBC批量插入100,000,000条数据,4096*8为一个批次。每张表总共12,500,000条数据(小于2000W条)。总共耗时为:2022秒。跟实验二不同的是实验三使用了3个Connection。因为是使用了三个数据库,没有办法使用相同的connection去插入。
数据库 | 表 | 表大小 | 连接数 | Batch | 总共插入数据 | 耗时时间(秒) | |
实验1 | 1 | 1 | 8.4G | 1 | 4096 | 100,000,000 | 2150 |
实验2 | 1 | 8 | 1.1G | 1 | 4096 | 100,000,000 | 2015 |
实验3 | 8 | 1 | 1.1G | 8 | 4096 | 100,000,000 | 2022 |
实验1 Postgre | 1 | 1 | NA | 1 | 4096 | 100,000,000 | 2339 |
读取实验
客户端环境,java8, spring-boot 2.6.6, sharing-sphere 3.1.0
实验一:使用上诉实验一的环境。共使用16个Connection。使用jmeter进行压力测试10 Thread,QPS 为826, 20 thread 889.
实验二:10 thread 833, 20 thread 944
实验三:10 thread 848, 20 thread 902
数据库 | 表 | 连接数 | 10 threads | 20 threads | |
实验1 | 1 | 1 | 16 | 826 | 889 |
实验2 | 1 | 8 | 16 | 833 | 944 |
实验3 | 8 | 1 | 2 | 848 | 902 |
跟预想的是一样的,分库分表并不能提高性能。
读取实验二
客户端环境,java8,使用多线程,JDBC来测试性能。
数据库 | 表 | 连接数 | 测试结果 | 测试结果 | |
实验1 | 1 | 1 | 8 | 5304.73 | 6086.77 |
实验2 | 1 | 8 | 8 | 7140.63 | 6467.98 |
实验3 | 8 | 1 | 8 | 5832.50 | 6614.85 |
实验1 | 1 | 1 | 16 | 14096.30 | 13497.41 |
实验1 | 1 | 1 | 24 | 18694.14 | 17823.77 |
实验1 | 1 | 1 | 32 | 19104.83 | 21274.47 |
也证明了分库分表不能明显提高性能,但是增加并发数可以有效的提高性能。因为mysql没有reactive的driver,就没有测试。
PS: 里面涉及大大量的取余的计算,我特意把除数都设置成2的几次幂,我以为编译器会可以帮我优化。但是查看class代码并没有进行优化。
然后又使用javac –O 测试,已经没有进行优化,不知道为什么。
问了一下ChatGPT,他就可以做出优化的解释。
也使用了一下https://www.cnblogs.com/BetterCallSaul/p/MySQL.html 提到的查看树高的方法。我的数据库使用的10W的时候是2层,但是到了20W就是3层了,1亿的时候也是三层。
ps: innodb_page_size 16384 (16K)
数据量 | 树高 |
100000 | 2 |
200000 | 3 |
300000 | 3 |
100000000 | 3 |
PS: 该文章是针对网上一些MYSQL性能不好,或者单表500W或者2000W需要进行分表。或者是为了减少树高的一些观念的看法。我觉得这些观点并不应该成为分库分表的主要目的。
摘自《阿里的开发手册》 。
Mysql单表最大记录是多少_mysql单表数据量_怎么又有bug单的博客-CSDN博客mysql单表最大记录数不能超过多少?https://blog.csdn.net/GBS20200720/article/details/125344782
分库分表的目的from ChatGPT
分库分表是一种常见的数据库水平扩展方案,它的主要目的是解决单一数据库的性能瓶颈和容量限制问题,提高系统的扩展性和可用性。
在单一数据库中,当数据量增长到一定程度时,会面临性能瓶颈和容量限制的问题。而分库分表可以将数据水平拆分到多个数据库或数据表中,每个数据库或数据表只负责一部分数据的存储和查询,从而提高了数据库的性能和容量。同时,分库分表也可以增加系统的可用性,当一个数据库或数据表出现故障时,只会影响到一部分数据,其他数据库或数据表仍然可以继续工作,从而保证了系统的正常运行。
除了提高系统性能和容量,分库分表还可以提高数据库的可扩展性。随着数据量的增长,可以通过增加数据库或数据表的数量来扩展系统的容量和性能,而不需要对原有的数据库或数据表进行修改或扩展。
总之,分库分表是一种解决单一数据库性能瓶颈和容量限制问题,提高系统可用性和可扩展性的有效方式。但是,在实际使用中需要考虑数据一致性、查询路由、数据迁移等问题,需要谨慎设计和实施。
我还是觉得chat GPT的答案挺好的。分库分表肯定有用处,但是我们在使用的时候需要评价我们的场景,以及带来的优缺点,然后我们需要权衡这些优缺点。不要一味的听说要分库分表,或者觉得“分库分表” 很高级。