MySQL 分库分表是一种数据库优化手段,通常用于应对数据量巨大、并发量高的场景。随着系统数据的增长,单个数据库可能难以承受高负载,进而影响性能和可扩展性。分库分表的目标是将数据分散到多个库或表中,从而减少单一库或表的压力,提高系统性能。
目录
一 我们为什么要分库分表?
1.性能问题:
- 数据量过大:当单个表的数据量非常大时,查询、插入、更新等操作的性能会明显下降。MySQL 性能通常随着单表数据量的增加而下降,数百万、数千万甚至更大的数据量可能导致响应时间变慢。
- 并发读写压力:当大量用户同时进行读写操作时,单个数据库实例可能承受不了高并发,造成数据库瓶颈和宕机风险。
2.扩展性问题:
- 存储瓶颈:数据库存储有上限,不可能无限扩展单个数据库实例的存储容量。如果数据量增长到单个数据库服务器难以承载的规模,就需要对数据进行切分。
- 数据库维护成本高:随着数据量和并发的增加,备份、恢复、迁移等运维工作会变得越来越困难和耗时。
3.业务需求:
当业务快速发展,数据量和用户量急剧增加时,使用分库分表可以保证系统的扩展性和高可用性。
二 怎么分:水平拆分与垂直拆分
1. 垂直拆分(竖着分)
垂直拆分是基于表的字段进行拆分,将一个表中的不同列拆分到不同的库或表中,通常用于优化查询效率、减少数据冗余。
分表之后,每个表的结构、数据都不一样,所有表的数据构成了原始数据集。通常表与表之间会存在至少一个关联字段,用于连接多表。
适用场景:
当表的列非常多时(上百列),部分列经常被使用,而其他列很少被访问。这时将常用的列和不常用的列分开存储,能够提高查询效率,减少数据冗余和磁盘 I/O。
表中的一些列较大且少用(如大字段、大文本、Blob 字段等),可以将这些字段独立出来存储,避免影响经常使用的字段的查询性能。
例如对于一个用户表 user
,包含用户的基本信息(如 id、name、email 等)和扩展信息(如详细地址、头像、个人简介等),可以将用户的基本信息和扩展信息分到不同的表中。
user_basic(id, name, email) -- 常用字段
user_extra(id, address, avatar, bio) -- 不常用字段
垂直拆分可以减少表的宽度,也就是减少每次查询时扫描的字段,提升查询效率,同时将不同业务模块分开,便于开发和维护。
但是垂直拆分后需要额外的维护成本,如拆分后需要处理关联查询,增加开发复杂度;拆分后可能依然无法解决单表行数过大的问题,仍需要水平拆分来进一步优化。
2.水平拆分(横着分)
水平拆分是基于表的行进行拆分,将同一个表中的不同数据分布到不同的库或表中。常用于解决单表数据量过大、查询和写入性能问题。
拆分后,每个表的结构是一样的,但是数据独立,均不一样,没有交集,所有表的数据共同构成了全部原始数据。
适用场景:
当单个表中的数据量非常大,导致查询、写入性能下降时。水平拆分能将数据分布到多个表或库中,减轻单表的负担。
适合业务规模扩展较大、用户群体广泛的数据处理场景,如电商、社交平台等。
例如有一个订单表 order
,每天有成千上万条订单记录,可以根据订单号、用户 ID、时间等字段对表进行水平拆分。
order_2021(id, user_id, order_amount, order_date)
order_2022(id, user_id, order_amount, order_date)
MySQL水平拆分通常使用的数据分片策略有两种:
1)范围分片:按时间、ID范围等,将数据切分到不同表或库中。
2)哈希分片:通过对某个字段(如用户 ID 或订单 ID)取哈希值,将数据均匀地分布到多个表或库中。
水平分片有利于分散数据压力,解决单表数据量过大、查询速度慢的问题,提升数据库的性能,而且可以根据业务规模的变化,逐渐增加新的分库或分表来扩展系统的容量,具有很强的扩展性。但是开发和运维的复杂性增加,因为当进行查询和插入操作时,需要额外逻辑判断该访问哪个库或表,而且会涉及分布式事务。
三 如何进行分库分表操作
1.判断是横向拆分还是纵向拆分
如果某些字段比较独立且较少被访问,或者表的字段特别多(几十甚至上百个),且访问时经常只需要部分字段,可以考虑垂直拆分。
如果表的行数非常大,影响了查询和写入性能,或者业务需求导致数据量增长迅速,预计将来会超过单表或单库的处理能力,可以考虑水平拆分。
2.拆分数量的判断
我们可以根据业务逻辑的模块、字段的访问频率等进行拆分,经常访问的字段可以保留在一个表中,较少访问或大字段(如图片、文档)可以独立拆分出去。
水平拆分可以根据表的数量进行预测,例如,如果预计未来数据量为 1 亿条,单表容量限制为 1000 万,则需要拆分为 10 个表。或者结合系统并发量、服务器容量和架构而定。
3.如何实现均匀拆分
哈希取模:根据某个字段(如用户 ID、订单 ID)取哈希值,然后对拆分表的数量取模,将数据分布到不同表或库中。哈希取模是一种非常常用的分片策略,能够确保数据均匀分布。
范围分片:根据某个字段的值范围进行划分,将数据分布到不同表中。例如根据订单日期进行分片。
一致性哈希:使用一致性哈希算法来分配数据,可以动态增加或减少节点(表或库),并且能保证数据分布均匀,适用于分布式系统中。
选择合理的分片键:分片键应当是查询时常用的字段,并且其值的分布要尽量均匀。避免选择高度聚集的字段(如创建时间、递增 ID 等),否则会导致数据倾斜。
避免热点:在某些情况下,特定的数据可能会成为访问热点,导致部分表或库的访问频率过高。为了避免这种情况,可以使用合理的分片策略(如哈希分片)来均衡负载。
动态扩容:当数据量持续增长,可以考虑通过增加分片表的数量来进行扩容。为了避免在扩容过程中发生数据倾斜,可以采用一致性哈希等动态分片算法。
标签:分库,拆分,MySQL,哈希,数据量,分片,分表,搞懂 From: https://blog.csdn.net/Liu_y_xin/article/details/141439971