分库分表

什么是分库分表?

分库:分库是将一个大型数据库分成多个数据库实例的过程。每个数据库实例通常被称为一个"分片"或"数据库分区"。分库的目的是将数据均匀分布在多个数据库中,以降低单个数据库的负载。
分表:分表是将一个数据库表分成多个子表的过程。每个子表通常包含表中的一部分数据。这种方式可以减小单个表的数据量,提高查询性能。

水平切分:水平切分是将数据按照行的方式分布在多个数据库或表中。每个分片存储数据的一部分。这通常用于处理大量数据。

垂直切分:垂直切分是将数据按照列的方式分布在多个数据库或表中。每个分片存储表中的一部分列。这通常用于将数据分为逻辑上相关的部分。

分片键:分片键是用于确定数据存储位置的关键字段或属性。它通常是在数据分片时选择的,以确保数据均匀分布。

为什么要分库分表?

这个答案很简单:数据库性能出现瓶颈
对外表现有几个方面:

数据库优化方案

数据库优化方案包括软件层面和硬件层面
软件层面:SQL调优、表结构优化、读写分离、数据库集群、分库分表等
硬件层面:增加机器性能

SQL 调优

SQL调优的目的就是尽可能让SQL命中索引,让慢SQL变快。
SQL调优一般有以下几个步骤:

  1. 首先开启慢SQL记录,明确知道慢SQL是哪个;
  2. 使用explain解析SQL,查看SQL的执行计划;
返回有一列叫“type”,常见取值有:
ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
ALL 代表这条 SQL 语句全表扫描了,需要优化。一般来说需要达到range 级别及以上。

表结构优化

根据业务场景进行表结构设计,如果涉及到连表查询,可以将部分字段作为冗余字段加入到业务表中,可以减少连表查询;
但是冗余字段存在一个弊端,该冗余字段会涉及到多个表的更新,因此选择冗余字段的时候需要选择不常更新的字段。

架构优化

分库

分库步骤:

  1. 单应用单数据库
  2. 多应用单数据库
  3. 多应用多数据库(根据业务将数据库进行拆分)

分表

如果系统处于高速发展阶段,拿商城系统来说,一天下单量可能几十万,那数据库中的订单表增长就特别快,增长到一定阶段数据库查询效率就会出现明显下降。

因此,当单表数据增量过快,业界流传是超过500万的数据量就要考虑分表了。当然500万只是一个经验值,大家可以根据实际情况做出决策。

那如何分表呢?

分表有几个维度,一是水平切分和垂直切分,二是单库内分表和多库内分表。

水平切分:表结构相同,数据不同

垂直拆分:表结构不同

分库分表实践

场景:目前有一张表存在上亿条数据,打算对该表进行分表,打算分为20个表,此时应该怎么做?横向分表

  1. 确定切分纬度(水平切分/垂直切分),根据业务id或其他字段进行表切分
  2. 数据备份,确保拆分过程数据不会丢失
  3. 使用分布式ID作为分表后的ID,并且与原表进行id对应
  4. 采用双写方式,确保老表与新分表的数据一致
  5. 数据对账,新表与老表的数据进行核对
  6. 查询路由,业务切流

分布分表带来的复杂性

既然分库分表这么好,那我们是不是在项目初期就应该采用这种方案呢?不要激动,冷静一下,分库分表的确解决了很多问题,但是也给系统带来了很多复杂性,下面简要说一说。

(1)跨库关联查询

在单库未拆分表之前,我们可以很方便使用 join 操作关联多张表查询数据,但是经过分库分表后两张表可能都不在一个数据库中,如何使用 join 呢?

有几种方案可以解决:

(2)分布式事务

单数据库可以用本地事务搞定,使用多数据库就只能通过分布式事务解决了。

常用解决方案有:基于可靠消息(MQ)的解决方案、两阶段事务提交、柔性事务等。

(3)排序、分页、函数计算问题

在使用 SQL 时 order by, limit 等关键字需要特殊处理,一般来说采用分片的思路:

先在每个分片上执行相应的函数,然后将各个分片的结果集进行汇总和再次计算,最终得到结果。

(4)分布式 ID

如果使用 Mysql 数据库在单库单表可以使用 id 自增作为主键,分库分表了之后就不行了,会出现id 重复。

常用的分布式 ID 解决方案有:

这些方案后面会写文章专门介绍,这里不再展开。

(5)多数据源

分库分表之后可能会面临从多个数据库或多个子表中获取数据,一般的解决思路有:客户端适配和代理层适配。

业界常用的中间件有:

参考: 我们为什么要分库分表