6936 字
35 分钟
100 道常见 MySQL 数据库题目高可用篇
2026-04-16 16:49:16

54. 数据库读写分离了解吗?#

答:

读写分离是 MySQL 高可用和高并发架构中非常常见的一种方案。 它的核心思想是:

把“写请求”和“读请求”分发到不同的数据库节点上执行。

通常情况下:

  • 主库(Master):负责写,也通常可以读
  • 从库(Slave / Replica):主要负责读

这样就能把大量读流量从主库分摊出去,提高整体吞吐能力。


1)为什么需要读写分离?#

在很多业务系统中,数据库的压力主要来自于读请求,而不是写请求。 比如:

  • 电商商品详情页
  • 用户信息查询
  • 文章列表页
  • 后台报表查询

这些场景通常“读多写少”。

如果所有请求都打到一台主库上,会带来问题:

  • 主库压力过大
  • 读写互相抢资源
  • 响应时间变慢
  • 可扩展性差

所以就引入读写分离:

  • 写操作依然只走主库
  • 读操作分发到一个或多个从库

2)读写分离的基本架构#

常见架构是:

  • 一主一从
  • 一主多从

例如:

应用服务
|
-----------------
| |
写请求 读请求
| |
主库 从库1 / 从库2 / 从库3

主库通过主从复制把数据同步到从库。 这样应用可以:

  • 写主库
  • 读从库

3)读写分离的好处#

(1)分担主库压力#

尤其是查询量很大的系统,效果明显。

(2)提升整体吞吐量#

多个从库可以并行承担大量读请求。

(3)提升可扩展性#

当读压力继续增大时,可以增加更多从库。

(4)一定程度提升可用性#

从库除了读,还可以在主库故障时用于切换或恢复。


4)读写分离适合什么场景?#

适合:

  • 读多写少
  • 查询压力大
  • 允许一定程度主从延迟
  • 高并发读场景

例如:

  • 内容平台
  • 电商商品系统
  • 社交信息流
  • 后台查询报表

5)读写分离会带来什么问题?#

它并不是没有代价,最典型的问题是:

主从延迟#

主库写完之后,从库不是绝对实时同步。 如果刚写完马上去从库查,有可能查不到最新数据。

例如:

  • 刚注册账号
  • 紧接着查询账号信息
  • 如果查从库,可能因为延迟而查不到

这就是“读写分离一致性问题”。


6)一句话总结#

读写分离的核心,就是主库负责写,从库负责读,用空间和架构复杂度换更高的读并发能力。


55. 那读写分离的分配怎么实现呢?#

答:

读写分离的关键不只是“有主从库”,更重要的是:

应用层怎么把写请求发到主库,把读请求发到从库。

常见实现方式有两种:

  1. 程序代码层实现
  2. 中间件层实现

1)程序代码层实现#

这种方式是指在业务代码中自己判断:

  • 当前 SQL 是读还是写
  • 应该连接主库还是从库

例如:

  • insert/update/delete 走主库
  • select 走从库

通常会在以下位置封装:

  • DAO 层
  • ORM 层
  • 数据源路由层
  • 连接池扩展层

优点

  • 灵活
  • 容易针对具体业务做特殊处理
  • 不一定需要额外中间件

缺点

  • 侵入业务代码
  • 容易写错
  • 维护成本高
  • 复杂场景不好统一管理

2)中间件层实现#

这种方式是引入数据库中间件,由中间件负责解析 SQL 并进行路由。

对应用来说,只连接一个中间件地址即可。 中间件内部再判断:

  • 读请求发到从库
  • 写请求发到主库

常见中间件包括:

  • MyCat
  • ShardingSphere
  • Atlas(较老)
  • ProxySQL

优点

  • 对业务代码侵入小
  • 路由规则统一管理
  • 扩展性强
  • 更适合大型系统

缺点

  • 增加一层基础设施
  • 运维复杂度上升
  • 中间件本身也可能成为瓶颈或故障点

3)实际如何判断读写?#

最简单的规则是:

  • SELECT 走从库
  • INSERT / UPDATE / DELETE / DDL 走主库

但真正线上系统没这么简单,因为还要考虑:

(1)事务中的查询#

如果一个事务里先写后读,这里的读通常也必须走主库,否则会有一致性问题。

(2)强一致性场景#

例如:

  • 注册后立即登录
  • 下单后立即查订单
  • 更新资料后立即查看详情

这些读请求常常也要走主库。

(3)从库延迟#

如果从库延迟过大,需要临时切回主库。


4)常见工程化方案#

方案一:框架自动路由#

例如 Spring 中通过 AOP 或动态数据源,在读方法上打注解:

@ReadOnly

自动走从库。

方案二:事务强制主库#

只要在事务中,所有操作都走主库。

方案三:关键接口强制主库#

对一致性要求高的接口,直接指定走主库。


5)一句话总结#

读写分离的分配,本质上是“SQL 路由”问题,常见做法是代码层路由或中间件路由。


56. 主从复制原理了解吗?#

答:

主从复制是 MySQL 高可用、读写分离的基础。 它的核心作用是:

把主库上的数据变更同步到从库。

这样从库就可以和主库保持大体一致,用于:

  • 读写分离
  • 数据备份
  • 故障切换
  • 灾备恢复

1)主从复制的核心流程#

主从复制大致流程可以概括为:

  1. 主库写数据
  2. 主库记录 binlog
  3. 从库拉取 binlog
  4. 从库重放 binlog
  5. 从库数据同步更新

2)详细过程#

第一步:主库执行写操作#

比如主库执行了一条:

UPDATE orders SET status = 2 WHERE id = 1001;

这条更新成功后,主库会把这次变更记录到 binlog 中。


第二步:主库把 binlog 提供给从库#

当从库连接到主库时,主库会创建一个 dump 线程(也叫 binlog dump thread)。

这个线程负责:

  • 读取主库 binlog
  • 把 binlog 内容发送给从库

第三步:从库 IO 线程接收 binlog#

从库上会有一个 IO 线程,它负责:

  • 连接主库
  • 接收主库推送的 binlog
  • 把接收到的内容写入本地 relay log(中继日志)

所以你可以理解为:

  • 主库 binlog 是原始变更日志
  • 从库 relay log 是中转日志

第四步:从库 SQL 线程重放 relay log#

从库还有一个 SQL 线程,负责:

  • 读取 relay log
  • 解析里面的事件
  • 在从库上重新执行这些操作

这样从库就把主库上的变更“重演”了一遍,最终达到数据同步。


3)一句话串起来#

主从复制可以概括为:

主库写 binlog -> 从库 IO 线程拉 binlog 写 relay log -> 从库 SQL 线程重放 relay log


4)为什么要 relay log?#

因为从库不能一边接收主库日志一边直接执行,否则耦合太强。 引入 relay log 后,可以把“接收”和“执行”分离:

  • IO 线程负责拉取
  • SQL 线程负责执行

这样架构更清晰,也便于恢复和排错。


5)主从复制默认是同步的吗?#

不是。 MySQL 常见主从复制默认是:

异步复制

也就是说:

  • 主库事务提交成功
  • 不需要等待从库一定执行完

这也是为什么会存在主从延迟。

后来也有:

  • 半同步复制
  • 组复制
  • 更强一致性的集群方案

但经典主从复制大多数是异步。


6)主从复制的意义#

(1)支持读写分离#

从库承担读请求。

(2)支持高可用切换#

主库挂了可以提升从库。

(3)支持备份和恢复#

可以基于 binlog 和从库做恢复。

(4)支持灾备#

异地从库可以用于容灾。


7)一句话总结#

主从复制的本质,是主库把 binlog 传给从库,从库通过 relay log 重放这些变更,从而实现数据同步。


57. 主从同步延迟怎么处理?#

答:

主从延迟是读写分离架构中最常见、最现实的问题之一。 它指的是:

主库上的数据已经更新成功,但从库还没来得及同步到最新状态。

这会导致:

  • 主库查得到
  • 从库查不到
  • 或从库查到旧数据

对于一些强一致业务场景,这个问题非常关键。


1)为什么会发生主从延迟?#

主从延迟的本质是:

主库写入速度 > 从库复制和重放速度

常见原因包括:

(1)主库写压力大#

短时间大量更新、插入,binlog 积压快。

(2)从库执行能力不足#

从库 CPU、IO、磁盘性能跟不上。

(3)慢 SQL / 大事务#

从库在执行 relay log 中某些 SQL 时耗时很长,导致后续复制堆积。

(4)锁等待#

从库回放过程中遇到锁竞争,也会拖慢复制速度。

(5)网络问题#

主从之间网络波动、延迟大,也会影响同步。


2)延迟会带来什么问题?#

最典型的问题就是:

写后读不一致#

例如:

  1. 用户注册成功(写主库)
  2. 立即去查询用户信息(读从库)
  3. 从库还没同步到,结果查不到

这类问题在:

  • 注册登录
  • 下单查单
  • 更新资料立即查看
  • 支付状态查询

中都很常见。


3)怎么处理主从延迟?#

常见方案有以下几种。


方案一:写后读走主库#

对于刚刚发生写操作后立刻要读的场景,直接让读请求走主库。

例如:

  • 注册后登录
  • 下单后查订单
  • 修改昵称后立刻刷新个人页

这是最常见、最稳妥的办法。

优点

  • 强一致
  • 实现简单

缺点

  • 对主库压力更大
  • 需要业务知道哪些读必须走主库

方案二:关键业务读写都走主库#

对于强一致性要求高的业务,直接不做读写分离。

例如:

  • 账户余额
  • 支付状态
  • 库存扣减
  • 交易订单状态

这些业务宁可牺牲一点读扩展性,也要保证正确性。


方案三:读从库失败后回源主库#

也叫“二次读取”。

思路是:

  1. 先查从库
  2. 如果查不到或版本不对
  3. 再回主库重查一次

优点

  • 对业务层侵入相对小
  • 大部分普通请求仍走从库

缺点

  • 实现复杂
  • 高峰期可能放大主库压力
  • 需要对异常场景做细致处理

方案四:监控延迟并动态摘除落后从库#

如果某个从库延迟太严重,可以临时不让它承担读流量。

常见做法:

  • 监控 seconds_behind_master
  • 超过阈值自动摘除
  • 恢复后再重新加入

适合中间件或数据库代理层来做。


方案五:优化复制链路本身#

从根本上减少延迟,包括:

(1)避免大事务#

大事务会让从库重放时间很长。

(2)拆分慢 SQL#

减少从库执行压力。

(3)提升从库配置#

增加 CPU、磁盘、内存性能。

(4)使用并行复制#

MySQL 新版本支持一定程度的并行复制,可提升从库 apply 速度。


方案六:使用更强一致性的复制方案#

如果业务对一致性要求很高,可以考虑:

  • 半同步复制
  • MGR(MySQL Group Replication)
  • Galera Cluster
  • 分布式数据库

不过复杂度和成本也会显著提升。


4)实际系统中的常见策略#

实际项目中常常是组合使用:

  • 普通查询走从库
  • 关键查询走主库
  • 写后短时间内读主库
  • 监控从库延迟
  • 延迟过高时自动切回主库

5)一句话总结#

主从延迟无法彻底消除,常见处理思路是“关键读走主库 + 监控延迟 + 优化复制性能”。


58. 你们一般是怎么分库的呢?#

答:

分库就是把原来放在一个数据库实例里的数据,拆分到多个数据库实例中。 它通常是为了解决:

  • 单库容量瓶颈
  • 单库性能瓶颈
  • 单机资源瓶颈
  • 高并发访问压力

分库一般分为两大类:

  1. 垂直分库
  2. 水平分库

1)垂直分库#

垂直分库是指:

按照业务模块,把不同的表拆到不同的数据库中。

例如一个电商系统原来所有表都在一个库里:

  • 用户表
  • 商品表
  • 订单表
  • 支付表
  • 物流表

后来可以按业务拆成:

  • 用户库
  • 商品库
  • 订单库
  • 支付库

垂直分库的特点#

优点

  • 业务边界清晰
  • 降低单库表数量
  • 降低库级别资源竞争
  • 更利于按业务独立扩展

缺点

  • 跨库 join 变复杂
  • 分布式事务问题出现
  • 业务开发复杂度增加

2)水平分库#

水平分库是指:

同一张表的数据,按某个规则拆到多个库中。

例如用户表原来所有用户都在一个库里,后来按用户 ID 哈希分到多个库:

  • user_db_0
  • user_db_1
  • user_db_2
  • user_db_3

每个库中都有一张用户表,但存的是不同范围/不同路由规则的数据。


水平分库的特点#

优点

  • 可以突破单库容量和性能瓶颈
  • 更适合海量数据场景

缺点

  • 路由复杂
  • 跨库查询复杂
  • 分布式事务更麻烦
  • 运维和扩容成本更高

3)什么时候用垂直分库?什么时候用水平分库?#

适合垂直分库的场景#

  • 系统业务模块很多
  • 不同业务之间相对独立
  • 单库里表太多
  • 不同业务读写压力差异大

适合水平分库的场景#

  • 某一张表数据量特别大
  • 单表 / 单库已经扛不住
  • 单业务已经达到海量数据规模

通常真实系统里,往往是先:

  • 垂直分库 再在某些热点业务里:
  • 水平分库

4)实际项目中怎么做?#

很多系统一开始单库就够用。 随着业务增长,常见演进路径是:

  1. 单库单表
  2. 垂直分库
  3. 热点表水平分库分表
  4. 中间件或自研路由

也就是说,分库不是一上来就做,而是随着规模增长逐步演进。


5)一句话总结#

分库一般分垂直分库和水平分库:垂直分库按业务拆,水平分库按数据拆。


59. 那你们是怎么分表的?#

答:

分表和分库类似,但粒度更细。 它是把原来的一张大表拆成多张小表,以解决:

  • 单表数据量过大
  • 索引膨胀
  • 查询变慢
  • 写入性能下降

分表一般也分为两类:

  1. 水平分表
  2. 垂直分表

1)水平分表#

水平分表是指:

表结构完全相同,但每张表只存一部分数据。

例如原来只有一张订单表:

orders

现在拆成:

  • orders_0
  • orders_1
  • orders_2
  • orders_3

每张表结构一样,只是存的数据不同。


水平分表常见规则#

  • 按 ID 取模
  • 按时间范围
  • 按用户 ID 哈希
  • 按业务路由表

适用场景#

  • 单表数据量太大
  • 查询和写入压力集中在一张表
  • 想降低单表索引高度和维护成本

2)垂直分表#

垂直分表是指:

按照字段维度,把一张宽表拆成多张表。

通常会拆成:

  • 主表(核心字段)
  • 扩展表(不常用字段、大字段)

例如用户表:

原始表:

  • id
  • name
  • phone
  • avatar
  • profile
  • intro
  • settings_json

可以拆成:

主表

  • id
  • name
  • phone

扩展表

  • user_id
  • avatar
  • profile
  • intro
  • settings_json

适用场景#

  • 表字段很多,行很宽
  • 大字段影响热点查询性能
  • 部分字段访问频率很低

3)分表和分库的区别#

  • 分表:还是在同一个数据库实例中拆表
  • 分库:拆到不同数据库实例

实际项目里,常常会先分表,再在必要时进一步分库。


4)一句话总结#

分表分为水平分表和垂直分表:水平分表按数据拆,垂直分表按字段拆。


60. 水平分表有哪几种路由方式?#

答:

水平分表之后,最关键的问题就是:

一条数据到底应该落到哪一张表?

这个过程就叫路由

常见的水平分表路由方式主要有三种:

  1. 范围路由
  2. Hash 路由
  3. 配置路由

1)范围路由#

范围路由是指:

按照某个有序字段的取值范围,把数据分配到不同表中。

例如按时间分表:

  • orders_202401
  • orders_202402
  • orders_202403

或者按 ID 范围分表:

  • user_0:1 ~ 100万
  • user_1:100万 ~ 200万

优点

  • 规则直观
  • 容易理解
  • 对按时间 / 范围查询很友好
  • 扩容时可以平滑增加新表

缺点

  • 数据可能分布不均
  • 热点可能集中在最新一张表
  • 某些范围可能特别大或特别小

2)Hash 路由#

Hash 路由是指:

根据某个字段做哈希或取模运算,把数据分配到不同表中。

例如按用户 ID:

user_id % 4

决定落到:

  • orders_0
  • orders_1
  • orders_2
  • orders_3

优点

  • 分布通常比较均匀
  • 热点相对容易打散
  • 实现简单

缺点

  • 不适合范围查询
  • 扩容麻烦,可能要重分布数据
  • 路由规则一旦定死,后续调整成本高

3)配置路由#

配置路由是指:

单独维护一张路由表,记录某条业务数据应该去哪张分表。

例如有一张:

order_router

里面存:

  • order_id
  • table_id

查询时先查路由表,再定位真实表。


优点

  • 灵活性最高
  • 可动态调整
  • 方便迁移数据和扩容

缺点

  • 多一次查询
  • 路由表本身也会变大
  • 维护复杂度高

4)怎么选择?#

范围路由适合

  • 按时间查询多
  • 数据天然有时间属性
  • 适合日志、订单、流水类业务

Hash 路由适合

  • 想尽量均匀分布数据
  • 等值查询多
  • 对范围查询要求不高

配置路由适合

  • 规则复杂
  • 迁移灵活性要求高
  • 需要手工控制分布策略

5)一句话总结#

水平分表常见路由方式有范围路由、Hash 路由和配置路由,分别在可读性、均匀性和灵活性上各有优劣。


61. 不停机扩容怎么实现?#

答:

不停机扩容是分库分表演进中的一个经典难题。 它的核心目标是:

在业务不停服的情况下,把原有库表的数据平滑迁移到新的库表结构。

这个过程本质上是:

  • 数据迁移
  • 双写同步
  • 切流量
  • 下线旧库

如果处理不好,可能会带来:

  • 数据不一致
  • 漏写
  • 读写异常
  • 线上故障

所以面试里通常会考你是否理解一个标准迁移流程。


1)第一阶段:新库准备 + 双写旧库和新库#

第一步:创建新库新表#

先把新的目标结构搭好,例如:

  • 新分表
  • 新分库
  • 新索引结构

第二步:上线双写逻辑#

此时应用层对写请求同时写:

  • 旧库
  • 新库

也就是说从某个时刻开始,增量数据同时进入两边。

这一步的作用

避免在历史数据迁移期间,新产生的数据只进入旧库,导致新库追不上。


2)第二阶段:迁移历史数据#

因为新库刚开始是空的,所以需要把旧库里的历史数据搬过去。

常见做法:

  • 分批迁移
  • 按主键范围迁移
  • 按时间批量迁移

注意点

  • 不能一次性全量大事务搬,容易影响线上
  • 要限速
  • 要可重试
  • 要保证幂等

3)第三阶段:数据校验和补偿#

历史数据迁移完成后,还要做校验,确保:

  • 旧库和新库数量一致
  • 关键字段一致
  • 没有漏数据、脏数据

常见做法:

  • count 校验
  • checksum 校验
  • 分片比对
  • 差异补偿任务

如果发现不一致,就补数据。


4)第四阶段:读流量切到新库#

当历史数据迁移完成,且双写也稳定、新旧数据比对无误后,就可以开始:

把读请求切到新库

注意此时通常还是保持双写:

  • 写:旧库 + 新库
  • 读:新库

这样即使发现问题,也还有旧库做兜底。


5)第五阶段:停止旧库写入并下线#

确认新库运行稳定后,再进入最后阶段:

  1. 停止旧库写入
  2. 只写新库
  3. 观察一段时间
  4. 确认旧库没有请求后,逐步下线旧库

6)为什么双写是关键?#

因为不停机扩容最大的问题不是“历史数据搬迁”,而是:

迁移期间业务还在不断产生新数据

如果没有双写:

  • 搬历史数据时旧库还在继续写
  • 等你搬完,旧库又新增了一批
  • 永远追不齐

所以通常需要:

  • 全量迁移
  • 增量双写
  • 校验补偿
  • 切换流量

7)这种方案的风险点#

(1)双写失败#

一边成功一边失败,容易导致不一致。

(2)顺序问题#

旧库和新库写入顺序不同,可能引发覆盖问题。

(3)幂等问题#

补偿任务重复执行可能造成脏数据。

(4)切流量时瞬间不一致#

读切换窗口如果控制不好,可能读到旧数据。

所以实际中通常会配合:

  • MQ
  • binlog 增量同步
  • 幂等控制
  • 校验程序
  • 灰度切换

8)一句话总结#

不停机扩容的核心流程是:新库建好 -> 双写 -> 历史迁移 -> 数据校验 -> 读切新库 -> 下线旧库。


62. 常用的分库分表中间件有哪些?#

答:

分库分表中间件的作用,是帮我们解决:

  • 数据路由
  • SQL 改写
  • 分片管理
  • 结果聚合
  • 读写分离(部分支持)

常见中间件主要有:

  1. ShardingSphere(Sharding-JDBC / Sharding-Proxy)
  2. Mycat

这是面试里最常见的答案。


1)ShardingSphere#

ShardingSphere 是目前比较主流的开源数据库中间件生态,原来叫:

  • Sharding-JDBC
  • Sharding-Proxy

现在归入 Apache ShardingSphere。


(1)Sharding-JDBC#

它是一个 客户端增强型框架。 直接嵌入到应用里,以 jar 包方式存在。

特点

  • 对业务透明度较高
  • 性能损耗相对低
  • 适合 Java 生态
  • 不需要额外部署代理层

缺点

  • 侵入应用
  • 强依赖语言生态
  • 多语言系统不方便统一

(2)Sharding-Proxy#

它是一个独立部署的代理服务。

应用连接它,就像连接数据库一样。 它负责路由 SQL 到后端实际分片库表。

特点

  • 对应用更透明
  • 支持多语言
  • 易于集中治理

缺点

  • 多一层代理
  • 运维复杂度更高

2)Mycat#

Mycat 是比较早期、比较知名的数据库中间件。 它工作在代理层,应用连接 Mycat,由 Mycat 转发到后端 MySQL。

支持能力

  • 分库分表
  • 读写分离
  • SQL 路由
  • 结果聚合

优点

  • 较早普及,社区影响力大
  • 对业务透明

缺点

  • 某些版本稳定性、维护性和兼容性曾被吐槽
  • 在现代新项目里,很多团队更偏向 ShardingSphere

3)怎么选?#

偏 Java 应用内嵌#

通常更倾向:

  • Sharding-JDBC

偏统一代理、多语言接入#

通常会考虑:

  • Sharding-Proxy
  • Mycat

新项目#

现在更多团队优先考虑:

  • ShardingSphere 生态

4)一句话总结#

常见分库分表中间件主要有 ShardingSphere 和 Mycat,其中现代项目更常用 ShardingSphere。


63. 你觉得分库分表会带来什么问题?#

答:

分库分表能解决单库单表的性能和容量瓶颈,但它不是没有代价。 它会把原本数据库帮你处理的很多事情,转移到:

  • 中间件
  • 应用层
  • 运维层

所以分库分表带来的问题非常多,这也是为什么它属于“最后手段”。

常见问题可以从以下几个方面来回答。


1)分布式事务问题#

单库时,本地事务很好处理。 一旦跨库操作,就可能涉及多个数据库实例。

例如:

  • 订单库写订单
  • 库存库扣库存
  • 支付库记账

这时一个本地事务就不够了,会变成分布式事务问题。

带来的挑战#

  • 一致性难保证
  • 实现复杂
  • 性能下降

常见解决方案:

  • 最终一致性
  • 可靠消息
  • TCC / SAGA
  • Seata 等框架

2)跨库 Join 问题#

在单库里可以直接:

SELECT ...
FROM order o
JOIN user u ON o.user_id = u.id;

但分库后,如果:

  • order 在订单库
  • user 在用户库

数据库本身就不能直接高效 join 了。

解决方式#

  • 业务层拼装
  • 冗余字段
  • 数据异构到 ES / 宽表
  • 中间件做有限聚合(通常性能有限)

3)跨节点分页、排序、聚合问题#

分表后,一个查询可能要访问多张表。 例如:

ORDER BY create_time DESC LIMIT 20

或者:

COUNT(*)
GROUP BY
SUM()

这些操作在分片环境下会变复杂:

  1. 每个分片先局部查询
  2. 再在中间层做汇总
  3. 再排序 / 分页 / 聚合

问题

  • 实现复杂
  • 性能开销大
  • 深分页尤其麻烦

4)全局唯一 ID 问题#

单库单表时可以直接依赖数据库自增主键。 分库分表后,如果每个分片都自增,就会出现主键冲突。

所以必须引入全局唯一 ID 方案,例如:

  • 雪花算法(Snowflake)
  • 号段模式
  • UUID(但不推荐做主键)
  • Redis / ZooKeeper 发号

5)扩容和数据迁移问题#

分库分表之后,如果原来的分片数不够用了,再扩容会很麻烦。

例如 Hash 分片:

  • 原来 4 张表
  • 现在变成 8 张表

路由规则变了,很多数据要重分布。 这就涉及:

  • 数据迁移
  • 双写
  • 校验
  • 切换流量

也就是上一题提到的“不停机扩容”难题。


6)路由规则复杂度问题#

分片后,应用必须知道:

  • 这条数据在哪个库
  • 在哪个表
  • 用哪个字段路由

如果路由字段传错、缺失,可能会:

  • 查不到数据
  • 扫描所有分片
  • 性能急剧下降

所以路由设计本身也是系统复杂度来源。


7)运维和排障复杂度上升#

单库时问题排查相对直接。 分库分表后:

  • 数据分散在很多节点
  • 慢 SQL 可能发生在某一个分片
  • 某个分片热点更严重
  • 主从、路由、中间件都可能出问题

这会导致:

  • 排障更复杂
  • 运维成本更高
  • 监控体系要求更高

8)数据热点问题#

即使做了分库分表,如果路由规则不合理,也可能出现热点。

例如:

  • 按用户 ID 哈希还比较均匀
  • 按时间范围分表时,最新表可能特别热

一旦热点集中到单分片,分片就失去了意义。


9)开发复杂度上升#

分库分表后,应用开发需要考虑更多事情:

  • 路由字段设计
  • 分页跨分片
  • 聚合跨分片
  • 事务一致性
  • 扩容迁移
  • SQL 兼容限制

原来一个简单 SQL 解决的问题,可能现在要多次查询 + 代码聚合。


10)一句话总结#

分库分表能解决容量和性能瓶颈,但会带来事务、跨库查询、聚合分页、全局 ID、扩容迁移和运维复杂度等一系列问题。

Comment seems to stuck. Try to refresh?✨