分库分表之拆分键设计

分库,分表,拆分,设计 · 浏览次数 : 767

小编点评

## 拆分键的选取和生成 拆分键是提高数据库性能的重要方法,它可以有效地降低单个数据库的负载,使其能够满足使用需求。在拆分过程中,需要考虑以下因素: * **拆分键的选取**: 选择一个能够有效拆分的维度,并以该维度进行查询的字段。 * **拆分键的生成**: 根据业务需求,选择合适的拆分键生成规则。 * **拆分后的索引**: 针对拆分后的表,建立索引可以加快查询效率。 **常用的拆分方法包括:** * **垂直拆分**: 将数据库及表垂直拆分成多个库或表。 * **水平拆分**: 将数据库及表水平拆分成多个库。 **拆分键的生成规则包括:** * **数据库自增主键**: 使用自增主键生成唯一标识符。 * **UUID**: 使用 UUID 生成唯一的标识符。 * **雪花算法**: 根据时间和机器信息生成唯一标识符。 **提升单数据库的性能的方法包括:** * **拆分**: 将多个数据库合并成一个数据库。 * **使用 NoSQL 数据库**: 例如 Cassandra 或 Redis,可以处理高并发的读写操作。 * **优化业务逻辑**: 针对拆分后的数据,优化业务逻辑以降低查询时间。 **拆分时需要注意的重点包括:** * **索引**: 为了提高查询效率,建立索引。 * **负载均衡**: 在拆分过程中,确保所有节点都能处理请求。 * **数据同步**: 在拆分后,需要对数据进行同步到 NoSQL 数据库中。 **总结:** 拆分键是提高单数据库性能的重要方法,可以有效地降低单个数据库的负载,使其能够满足使用需求。选择和生成合适的拆分键和索引,以及优化业务逻辑,可以提升数据库的性能。

正文

众所周知,在现实世界中,每一个资源都有其提供能力的最大上限,当单一资源达到最大上限后就得让多个资源同时提供其能力来满足使用方的需求。同理,在计算机世界中,单一数据库资源不能满足使用需求时,我们也会考虑使用多个数据库同时提供服务来满足需求。当使用了多个数据库来提供服务时,最为关键的点是如何让每一个数据库比较均匀的承担压力,而不至于其中的某些数据库压力过大,某些数据库没什么压力。这其中的关键点之一就是拆分键的设计。

1 水平、垂直拆分

在关系数据库中,当单个库的负载、连接数、并发数等达到数据库的最大上限时,就得考虑做数据库和表的拆分。如一个简单的电商数据库,在业务初期,为了快速验证业务模式,把用户、商品、订单都放到一个数据库中,随着业务的发展及用户量的增长,单数据库逐渐不能支撑业务(MySQL中单记录容量超过1K时,单表数据量建议不超过一千万条),这时就得考虑把数据库和表做出拆分。

1.1 垂直拆分

简单的说就是将数据库及表由一个拆分为多个,如我们这里的电商数据库,可以垂直拆分为用户数据库、商品数据库和订单数据库,订单表可以垂直拆分为订单基本信息表,订单收货地址表、订单商品表等,每一个表里保存了一个订单的一部分数据。

1.2 水平拆分

简单的说就是将一个库、一个表扩展为多个库,多个表,每一个拆分后的表中保存的依然是一个订单的完整信息。如电商数据库,我们按水平拆分数据库和表后,每一个拆分后的数据库表与现有未拆分前的都保持一致。

1.3 常用拆分方法

上述仅从理论上讲解了可行的水平、垂直拆分方法,在实际的生产上,我们拆分一般是按照水平拆表、垂直拆库这一原则进行,在业务比较复杂的场景下也会对表进行垂直拆分。

2 拆分键的选取

分库分表的关键项之一是拆分键的选取,一般情况下,拆分键的选取遵循以什么维度进行查询就选取该维度为拆分键。如:订单表就以订单号作为拆分键,商品表就以商品编号作为拆分键。拆分键选取后,对于一些非拆分键的单条件查询,我们需要怎么支持呢?在这里提供3种方法供参考。

2.1 等值法

对于非拆分键的单条件查询,对这一个单条件的赋值,可以将其值与拆分键保持一致。比如在电商场景中,用户下订单后,需要通过物流给用户把商品送到用户手上。对于用户来说仅能看到订单信息,订单上展示的物流信息用户也是通过订单号查询而来;但对于物流系统来说,其系统里的业务主键(拆分键)是运单号,此时,运单号如果和订单号相同,即可完美解决这一问题。订单表和运单表的基本数据模型如下:

1)订单表

2)运单表

在订单表中,拆分键order_id与运单表中的拆分键waybill_code值相同,当按订单号查询运单表里的运单信息时,可以直接查询拆分键waybill_code获取订单对应的运单信息。

2.2 索引法

对于常用的非拆分键,我们可以将其与拆分键之间建立一个索引关系,当按该条件进行查询时,先查询对应的拆分键,再通过拆分键查询对应的数据信息。订单表的索引法查询表模型如下:

1)索引表

例:用户user001在商城上购买了一支笔下单的订单号为10001,商家发货后,物流公司给的运单号是Y0023

2)该用户的订单表、运单表模型如下:

订单表:

运单表:

索引表:

当查询用户(user001)的下单记录时,通过用户编码先查询索引表,查询出user001的所有下单的订单号(10001),再通过订单号查询订单表获取用户的订单信息;同理,根据运单号(Y00232)查询订单信息时,在索引表里先查询到对应的订单号,再根据订单号查询对应的订单信息。

2.3 基因法

拆分键与非拆分键的单号生成规则中,存在相同规则的部分且该部分被用作拆分键来进行库表的定位。比如:订单号生成时,生成一个Long类型的单号,由于Long是64位的,我们可以用其低4位取模来定位该订单存储的数据库及表,其他表的拆分键也用Long类型的低4位取模来定位对应的数据库及表。还是用订单表和运单表的模型做解释如下:

1)订单表

2)运单表

当通过订单表里的订单号查运单表时,通过订单号的低4位定位到该订单号在运单数据库及表的位置,再直接通过脚本查询出订单号对应的运单信息。

3 拆分键的生成

拆分键选取后,接下来是拆分键的生成,拆分键的生成有多种方式,建议根据业务量及并发量的大小来确定拆分键生成的规则,在这里介绍几种常用的拆分键生成规则。

3.1 数据库自增主键

在并发量不大的情况下,我们可以使用MySQL数据库里的自增主键来实现拆分键。

3.2 UUID

在Java里,可以使用Java自带的UUID工具类直接生成,UUID的组成:UUID=当前日期和时间+时钟序列+全局唯一的IEEE机器识别号组成。其中,全局唯一的IEEE机器识别号一般是通过网卡的MAC地址获得,没有网卡时以其他的方式获得。UUID生成的编号不会重复,但不利于阅读和理解。

import java.util.UUID;

public class UUIDTest {
    public static void main(String[] args) {
        UUID uuid = UUID.randomUUID();
        System.out.println(uuid.toString());
    }
}

3.3 雪花算法

雪花算法生成的ID是一个64位大小的整数,结构如下:

从其结构可以看出,第一位是符号位,在使用时一般不使用,后面的41位是时间位,是由时间戳来确定的,后面的10位是机器位,最后的12位是生成的ID序列,是每豪秒生成的ID数,即每毫秒可以生成4096个ID。从该结构可以看出,10位机器位决定了使用机器的上限,在某些业务场景下,需要所有的机器使用同一个业务空间,这可能导致机器超限;同时,每一个机器分配后如果机器宕机需要更换时,对ID的回收也需要有相应的策略;最为关键的一点是机器的时间是动态调整的,有可能会出现时间回退几毫秒的情况,如果这个时候获取到这个时间,则会生成重复的ID,导致数据重复。

4 提升总结

单数据库不能满足业务场景的情况下,主要的思路还是要进行拆分,无论是NoSQL还是关系数据库,随着业务量的增长,都得需要把多个服务器资源组合成一个整体共同来支撑业务。数据库拆分后,如果业务上有多个复杂查询条件的需求,一般就得把数据同步到NoSQL数据库里,由NoSQL来提供支持。无论什么时候,数据库提供的主要能力是存储能力,对于复杂的计算需求,一般是需要在业务逻辑里实现。

作者:京东物流 廖宗雄

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

与分库分表之拆分键设计相似的内容:

分库分表之拆分键设计

当使用了多个数据库来提供服务时,最为关键的点是如何让每一个数据库比较均匀的承担压力,而不至于其中的某些数据库压力过大,某些数据库没什么压力。这其中的关键点之一就是拆分键的设计

[转帖]Shell编程之正则表达式与文本处理器(grep、sort、uniq、tr、cut)

目录 正则表达式概念正则表达式的作用元字符grep命令在文本中查找指定的字符串sort命令排序uniq命令快捷去重tr命令替换、压缩和删除cut命令快速裁剪命令expr substr 截取方法cut截取方法 split命令文件拆分paste命令文件合并eval变量扫描器位置锚定分组或其他扩展正则表达

微服务项目搭建之技术选型

1、什么是微服务 Java微服务是一种架构风格,通过将单个Spring Boot应用程序拆分为一组小型、独立的Spring Boot服务来构建分布式系统。每个微服务都运行在自己的进程中,并使用轻量级通信机制(如HTTP或消息队列)来进行相互之间的通信。微服务的设计目标是提高系统的灵活性、可伸缩性和可

MySQL 分表查询

分表是一种数据库分割技术,用于将大表拆分成多个小表,以提高数据库的性能和可管理性。在MySQL中,可以使用多种方法进行分表,例如基于范围、哈希或列表等。下面将详细介绍MySQL如何分表以及分表后如何进行数据查询。 基于哈希的分表 基于哈希的分表是一种将数据分散到多个子表中的数据库分表策略。这种方法通

分而治之 -- 浅谈分库分表及实践之路

今天想聊一下分库分表,因为对于快速增长的业务来说,这个是无法回避的一环。之前我在做商城相关的SAAS系统,商品池是一个存储瓶颈,商品池数量会基于租户增长和运营变得指数级增长,短短几个月就能涨到几千万的数据,而运营半年后就可能过亿。而对于订单这种数据,也会跟着业务的成长,也会变得愈发巨大。

[转帖]一个空格导致应用启动失败的问题排查

2021-02-03 分类:Java / spring 阅读(2930) 评论(2) GitHub 24k Star 的Java工程师成神之路,不来了解一下吗! 先交代一下背景,在很久之前,我曾经封装过一个分库分表的扫表工具——Full Table Scanner,主要实现方式是通过使用TDDL H

[转帖]MySQL索引优化分析之性能分析(Explain执行计划)

一、MySQL常见瓶颈 二、性能分析工具Explain(执行计划 ) 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。查看官网说明: 使用: Explain + SQL语句 作用: 三、各字段解释 3.1、

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程(转载)

https://cloud.tencent.com/developer/article/1420726 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程

https://www.cnblogs.com/wx170119/p/12068005.html 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候,有

[转帖]性能分析之TCP全连接队列占满问题分析及优化过程(转载)

https://www.cnblogs.com/wx170119/p/12068005.html 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如何进行分析及解决的。 理解下TCP建立连接过程与队列 从图中明显可以看出建立 TCP 连接的时候,有