SQL数据库分库分表设计及常见问题
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
文章导读背景介绍 随着互联网技术的发展,数据量呈爆炸性增长。大数据量的业务场景中,数据库成为系统性能瓶颈的一个主要因素。当单个数据库包含了太多数据或过高的访问量时,会出现查询缓慢、响应时间长等问题,严重影响用户体验。为了解决这一问题, 场景分析例如:在交易系统核心数据库设计大致包括: 产品数据库(Product/Asset Database):存储系统可交易的产品或资产的详细信息,比如在股票交易系统中,这里会包含股票代码、股票名称、当前价格等信息。 订单数据库(Order Database):存储用户提交的订单信息,包括订单ID、订单状态(如待处理、完成、取消)、订单创建时间等。 用户数据库(User Database):存储用户的基本信息,如用户ID、用户名、密码(通常进行加密存储)、联系信息等,以及用户的权限和角色定义。 交易数据库(Transaction Database):记录所有交易的详细信息,如交易ID、交易类型(买入、卖出等)、交易金额、交易时间、交易双方等。这个数据库是交易系统的核心,需要高效且可靠。 配置数据库(Configuration Database):存储系统配置信息,如交易规则、费用设置、系统参数等。 历史数据库(Historical Data Database):保存交易、订单和价格的历史记录。这对于数据分析、报告生成及监控非常重要。 账户数据库(Account Database):存储用户的账户信息,包括账户余额、账户类型、账户状态等。在交易系统中,账户信息是核心数据之一。 安全和审计数据库(Security and Audit Database):用于记录安全相关的事件,如登录尝试、权限变更等,以及审计记录,确保系统的安全性和可追踪性。 ...... 从上边的分析看,对应数据库表大致归纳为以下几种类型:
...... 思考一般哪些表可能存在数据激增、性能问题?日志表、流水表、用户表等都可能。而系统配置则可能相对较少。 分库分表
分库分表是一种数据库架构优化技术,说白了就是一种 以订单库 db_order 和 订单表 tb_order 为例(db为库,tb为表): 水平分库:根据某些规则(例如订单ID的范围)将db_order数据库分成多个数据库(分片),如db_order_1, db_order_2, db_order_3等。每个数据库的表结构相同,但存储的订单数据不同。 水平分表:根据订单的创建时间,将tb_order分成tb_order_2022, tb_order_2023, tb_order_2024等多个表,每个表存储各自时间段的订单数据。表结构保持一致,但每个表只存储一部分数据。 垂直分库:根据业务功能将数据垂直分割到不同的数据库中。例如,将订单相关的表保留在db_order中,将用户相关的表迁移到新的数据库db_user中,商品相关的表迁移到db_product中。 垂直分表:若tb_order表中的字段非常多,包含了订单的基本信息、订单属性信息、订单资费信息等多个方面。此时,可以将tb_order表垂直拆分为多个表,如tb_order_base存储订单的基本信息,tb_order_chars存储订单属性信息、tb_order_charges存储订单资费信息。 小结 有了以上这些了解,基本对分库分表概念有了大致了解。对于分库一般按照 分库分表常见问题
参考规则根据《阿里巴巴Java开发手册》,给出如下建议: 工程经验事实上,通常在实战中,一般按经验数据达到千万级,就需要分库分表。原因如下: 我们知道:InnoDB管理磁盘的最小单元:页,页大小16KB.
在日常开发中,对于数据库性能优化,我们首先想到的是 图片来源于网络,侵权删 树高为3的B+树数据存储计算规则: 根节点计算: 假设数据类型是bigint,大小为8b。数据本身也需要一小块空间,用来存储下一层索引数据页的地址,大小为6b, 那么根节点是可以存储16*1024/(8+6) = 1170 个数据。 其它层节点计算: 第二层:因为每个节点数据结构和跟节点一样,而且在跟节点每个元素都会延伸出来一个节点,所以第二层的数据量是1170*1170=1368900 第三层:因为innodb的叶子节点,是直接包含整条mysql数据的,假设每条数据以1kb计算,那么第三层每个节点为16kb,那么每个节点是可以放16个数据的,所以最终mysql可以存储的总数据为 1170 * 1170 * 16 = 21902400 (千万级) 其实计算结果与我们平时的工作经验也是相符的,一般mysql一张表的数据超过了千万也是得进行分表操作了。 参考文章: MySQL一张表到底能存多少数据?[1]
例如,本节我们以订单表的分表为例,一般订单表中含有订单编号:order_id, 用户编号:user_id, 订单创建时间:order_date等。 对于订单表,通常我们可以考虑以下分片键选项: 订单编号 优点:订单编号通常是唯一的,可以确保每个订单都分散到不同的分片上。这对于保证数据均匀分布和避免热点数据非常有帮助。 用户编号 优点:用户编号通常也是唯一的,并且如果用户的订单量分布均匀,那么使用用户编号作为分片键可以确保每个用户的订单都在同一个分片上,这对于查询某个用户的所有订单非常高效。 缺点:如果用户的订单量差异很大,那么某些分片可能会存储大量的订单数据,而其他分片可能只有少量的数据。这会导致数据分布不均匀,进而影响查询性能。 订单创建时间 优点:适用于:按时间范围查询订单的场景。 缺点:可能出现热点数据倾斜问题(即在某个时段产生订单峰值)
在选择主键策略时,需要注意以下几点:
在 MySQL 中进行分库分表时,自增主键策略确实需要特别处理,因为传统的自增主键策略在分布式环境下会导致主键冲突。每个数据库实例或分片都会从相同的起始点开始自增,这会导致在不同的分片上生成相同的 ID,进而引发数据冲突。 几种常见的主键策略方案:
UUID 是一个 128 位的值,具有全局唯一性,可以很好地解决分布式环境下的主键冲突问题。但是,UUID 字符串较长,存储和索引效率较低,而且是无序的,可能会影响查询性能。
通过这种结构,雪花算法可以保证生成的ID按时间递增,并且整个分布式系统中不会有重复的ID。
总之,在分库分表时,自增主键策略需要进行特殊处理,以确保全局唯一性,并根据实际情况选择合适的方案。
选择分库分表的策略时,确实需要根据具体的业务场景和数据特性来决定。例如订单表,以订单ID ( 基于范围的策略适用场景:当订单ID有明确的增长趋势,例如连续的自增ID,并且你知道未来可能的订单数量时,范围分表是一个好选择。 策略实现:可以将订单ID按照范围划分到不同的表中。例如,订单ID【1-1000万】 在表 优点:
缺点:
基于哈希的策略适用场景:当订单ID没有明确的增长趋势,哈希分表是一个好选择。 策略实现:使用哈希函数对订单ID进行哈希运算,然后根据哈希值的结果决定存储在哪个表中。
优点:
缺点:
映射表策略适用场景:当订单ID的分布不均,或者需要灵活控制数据分布时,映射表分表可能是一个好选择。 策略实现:使用一个映射表来记录每个订单ID应该存储在哪个表中。这个映射表可以是内存中的数据结构,也可以是数据库中的一个表。 优点:
缺点:
一致性哈希策略适用场景:当系统需要高可用性,并且希望在添加或删除节点时尽量减少数据迁移时,一致性哈希可能是一个好选择。 策略实现:使用一致性哈希算法将订单ID映射到哈希环上,然后根据哈希环上的节点(或表)来存储数据。 一致性哈希算法的核心思想是将哈希值空间表示为一个闭合的圆环(哈希环),每个节点负责维护圆环上一段连续的哈希值范围。 在分库分表的场景中,可以将每个数据库或表看作是一个节点,将这些节点均匀地分布在哈希环上。当插入或查询数据时,根据数据的哈希值将其映射到哈希环上,然后顺时针查找最近的节点(即负责该哈希值范围的数据库或表),将数据插入或查询该节点。 优点:
缺点:
曾几何时,面试过程中遇到过这样一个问题:假设有一个用户表,你用ID做的分片键,那么有一个类似于name这样的字段如何查询? 这里提供几种常见的思路: 1.全局索引全局索引是一个跨所有分片的索引,它包含了非分片键字段和对应的分片键信息。查询时,先通过全局索引找到相关的分片键,然后在相应的分片中查询详细数据。 适用场景:适用于查询频率高、数据量大的非分片键字段。 优点:查询效率高,可以快速定位到数据所在的分片。 缺点:全局索引维护成本较高,需要定期更新以保持与分片数据的一致性。 2. 数据冗余在每个分片中存储部分非分片键字段的数据。这样,即使不直接查询分片键,也可以在分片内快速找到相关数据。 适用场景:适用于查询性能要求极高,且可以接受一定数据冗余的场景。 优点:查询性能高,无需跨分片查询。 缺点:数据冗余增加了存储成本和维护复杂性。 3. 应用层处理在应用层实现复杂的查询逻辑,将多个分片中的查询结果汇总后进行处理。 适用场景:适用于查询频率不高,或者可以接受一定延迟的场景。 优点:灵活性高,可以根据业务需求定制查询逻辑。 缺点:查询性能可能受到网络延迟和分片数量的影响。 4. 使用Elasticsearch(ES)将非分片键字段的数据同步到Elasticsearch中,利用Elasticsearch强大的搜索和查询能力进行查询。 适用场景:适用于非结构化数据、全文搜索、复杂查询等场景。 优点:支持复杂的查询操作,如全文搜索、模糊匹配等;查询性能高,支持分布式部署。 缺点:需要维护Elasticsearch集群,增加了系统的复杂性;数据同步可能引入一定的延迟。 5. 数据库中间件使用数据库中间件(如ShardingSphere、MyCAT等)来管理分库分表,中间件可以自动处理非分片键字段的查询,将请求路由到正确的分片。 适用场景:适用于希望减少应用层复杂性的场景。 优点:简化了应用层的查询逻辑,减少了开发和维护的工作量。 缺点:需要配置和维护数据库中间件。 总结在实际应用中,可能需要根据实际情况结合多种策略来满足不同的查询需求。同时,随着业务的发展和数据量的增长,可能需要不断调整和优化分库分表策略。
热点数据倾斜通常发生在某些特定的数据项(例如,用户激增、促销订单峰值等)等,导致这些数据的查询和更新操作集中在些某特定的数据库或表上,从而造成性能瓶颈。 解决方案:采用
分库分表后,数据被分散到了不同的数据库或表中。跨库关联查询成为新的问题。为了解决这个问题,可以采取以下几种策略:
需要注意的是,虽然上述方法可以解决跨库关联查询的问题,但它们也会带来一些额外的复杂性。在设计分库分表方案时,需要综合考虑业务需求、数据量、查询频率等因素,选择合适的策略来平衡性能和可维护性。同时,随着业务的发展和数据量的增长,可能需要对分库分表方案进行调整和优化。
分库分表后,排序和分页问题变得相对复杂,因为数据不再集中在一个单一的数据库或表中。解决这些问题需要综合考虑多种因素,包括数据量、查询频率、业务需求等。以下是一些解决分库分表后排序和分页问题的策略: 排序问题
分页问题
当数据量逐渐增加,需要进行分库分表的扩容时,可以从以下几个方面来考虑和制定策略: 1. 数据增长评估首先,要对数据的增长趋势进行准确的评估。通过分析历史数据、业务发展趋势以及用户增长情况,可以预测未来的数据量增长情况。一般预估未来3~5年的数据增长。 2. 选择合适的分片键选择一个合适的分片键是分库分表的关键。分片键应该能够均匀分布数据,避免某些数据库或表过载。同时,分片键的选择也要考虑到查询性能和数据一致性等因素。 3. 实施扩容基于数据增长趋势和分片键的选择,制定详细的扩容计划。这包括确定扩容的时间点、扩容的目标规模、数据迁移和重新分配的策略等。确保扩容过程能够顺利进行,尽可能减少对业务的影响。 4. 数据迁移与重新分配在扩容过程中,需要进行数据迁移和重新分配。这通常涉及到将现有数据从旧的数据库或表迁移到新的数据库或表中。可以使用数据迁移工具或自动化脚本来完成这个过程,确保数据的完整性和一致性。 5. 负载均衡在扩容后,需要确保数据在新旧数据库或表之间均匀分布,以实现负载均衡。可以使用负载均衡器或支持分库分表的中间件来动态分配请求,确保系统的性能和稳定性。 6. 监控与调优在扩容过程中和扩容后,需要对系统进行持续的监控和调优。通过监控数据库或表的负载情况、查询性能等指标,及时发现并解决性能瓶颈和故障。同时,根据实际需求进行调优,如调整索引、优化查询语句等,以提升系统的整体性能。
业界常用的分库分表中间有:Sharding和MyCat
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。ShardingSphere提供 优点:
缺点:
Mycat是一个开源的、跨平台的、基于MySQL协议的数据库中间件,支持SQL分析、SQL解析、SQL路由、SQL改写、SQL执行和结果归并等功能。Mycat可以实现透明的 优点:
缺点:
分库分表后,因为数据分布在不同的数据库和表中,需要确保不同数据库实例间的事务一致性。解决这类分布式事务问题,可以参考个人的其它历史文章: 总结分库分表技术总结 一、分库分表策略 分库分表(Sharding)是一种将单一数据库拆分为多个数据库实例,以及将单一大表拆分为多个小表的技术策略。其目的是解决单一数据库在数据量、并发访问、性能等方面的瓶颈,提升系统的整体性能和可靠性。 常见的分库分表策略包括:
二、分库分表常见问题
此外,对于某些不适用分库分表的场景,或者希望简化分布式数据库管理的复杂性,可以考虑使用TiDB。 参考文章链接: https://mp.weixin.qq.com/s/SuJ-XCaVegVunOIf69-9AQ 结尾共享即共赢。如有帮助,帮忙点赞和在看。关注公众号【码易有道】,定期更新一些工程实践的总结和个人心得。欢迎你的加入,一起学习、交流、做长期且正确的事情!!! MySQL一张表到底能存多少数据?: https://www.php.cn/faq/500130.html 该文章在 2024/3/30 16:46:28 编辑过 |
关键字查询
相关文章
正在查询... |