# 什么是分库分表?分库分表有哪些类型(或策略)?
8 min read
Table of Contents
什么是分库分表?分库分表有哪些类型(或策略)?
分库分表面试标准答案
【核心定义】
分库分表是一种数据库水平拆分技术,通过将单一数据库/表的数据分布到多个数据库/表中,以解决单库单表在数据量、并发量、磁盘IO等方面遇到性能瓶颈的问题。
【关键要点】
-
分库(Database Sharding)
将数据按规则分散到多个物理数据库中,每个数据库实例独立运行,主要解决数据库连接数瓶颈和单机硬件资源限制问题。 -
分表(Table Sharding)
将单表数据按规则拆分到多个物理表中(通常在同一数据库内),主要解决单表数据量过大导致的查询性能下降、索引膨胀问题。 -
拆分策略类型
- 垂直拆分:按业务模块/功能拆分(如用户库、订单库)
- 水平拆分:按数据行拆分(如按用户ID取模分表)
- 混合拆分:先垂直后水平,实际生产中最常用
【深度推导/细节】
核心矛盾与解决方案拆解
矛盾1:单表数据量过大(>5000万行)
- 问题:B+树索引深度增加,磁盘IO次数增多,DDL操作锁表时间长
- 解决方案:水平分表,将单表拆分为多个小表(如
order_0~order_7)
矛盾2:数据库连接数瓶颈
- 问题:单机MySQL最大连接数有限(默认151),高并发时连接耗尽
- 解决方案:分库部署,每个库独立连接池,总连接数 = 单库连接数 × 库数量
矛盾3:热点数据集中
- 问题:某些分片负载过高(如按时间分表时,当前月份表压力大)
- 解决方案:采用复合分片键(如
用户ID+月份),或引入一致性哈希算法
扩容机制逻辑拆解
Step 1:预分片设计
- 初始设计时预留扩展空间(如按64个分片设计,初期只启用16个)
Step 2:数据迁移过程
1. 双写策略:新老分片同时写入2. 数据同步:将历史数据迁移到新分片3. 校验数据:确保数据一致性4. 流量切换:逐步将读请求切换到新分片5. 停写老分片:确认无误后停止向老分片写入Step 3:路由规则更新
- 动态配置中心更新分片规则
- 应用重启或热加载新配置
【关联/对比】
| 维度 | 分库 | 分表 | 适用场景 |
|---|---|---|---|
| 拆分粒度 | 数据库级别 | 表级别 | 分库解决连接瓶颈,分表解决数据量瓶颈 |
| 事务支持 | 分布式事务复杂 | 本地事务可用 | 分表更容易保持事务一致性 |
| 跨库查询 | 需要中间件聚合 | 相对简单 | 分表对应用透明性更好 |
| 扩容成本 | 较高(涉及数据迁移) | 较低(可局部扩容) | 分表扩容更灵活 |
与读写分离对比:
- 读写分离:解决读多写少场景,通过主从复制分摊读压力
- 分库分表:解决数据量大/写并发高场景,本质是数据分布问题
与NoSQL对比:
- NoSQL(如MongoDB)天生支持分片,但事务能力弱
- 分库分表是在关系型数据库上实现类似能力,保持ACID特性
『面试官追问』
-
如何选择分片键?
- 选择基数大、分布均匀的字段(如用户ID)
- 避免选择单调递增字段(如自增ID)导致热点
- 常用方案:业务主键取模、一致性哈希、范围分片
-
分库分表后如何实现全局唯一ID?
- 雪花算法(Snowflake):64位,包含时间戳+机器ID+序列号
- 数据库号段模式:批量获取ID段,内存分配
- UUID:但索引效率低,不适合做InnoDB主键
-
跨分片查询如何优化?
- 禁止多表JOIN跨分片查询
- 采用冗余字段或宽表设计
- 复杂查询走Elasticsearch等搜索引擎
- 分页查询需在各分片查询后内存聚合
-
分库分表后事务如何处理?
- 尽量设计为单库事务
- 使用Seata等分布式事务框架(2PC/XA)
- 最终一致性方案(消息队列+本地事务表)
-
实际生产中的拆分时机?
- 单表数据量:>5000万行或>50GB
- 并发连接数:持续>最大连接数80%
- 查询响应时间:核心业务>500ms且优化无效
- 建议:提前规划,避免被动拆分
【直击痛点:关键数字与设计合理性】
- 5000万行阈值:InnoDB B+树3层高度可存储约5000万行(按16KB页大小,主键8B计算),超过后树变4层,IO次数增加
- 64个分片上限:过多分片导致连接池膨胀、维护复杂,通常建议2的n次方(16/32/64)便于取模运算
- 双写过渡期:通常设置1-2周,确保数据完全同步
- 分片键选择:80%查询应能通过分片键直接定位,避免广播查询
【版本差异与实践演进】
- 早期方案:应用层硬编码分片逻辑(2015年前)
- 中间件时代:MyCAT、ShardingSphere(2015-2020)
- 云原生时代:Vitess(K8s)、PolarDB分布式版(2020至今)
- 趋势:从应用层拆分 → 中间件代理 → 数据库原生支持
最佳实践总结:分库分表是“不得已而为之”的优化手段,应优先考虑读写分离、索引优化、归档历史数据等方案。当必须拆分时,建议采用“垂直拆分优先,水平拆分谨慎”的原则,并选择成熟的中间件(如ShardingSphere)降低开发复杂度。