MySQL 分库分表怎么做?

2025年 阅读约 15 分钟 面试指南 · MySQL

深入解析MySQL分库分表方案:垂直拆分vs水平拆分、分片策略(范围/哈希/一致性哈希)、ShardingSphere实战、数据迁移方案、全局ID生成,附面试模拟问答。

一句话总结

分库分表是解决单表数据量过大的方案。分为垂直拆分(按业务拆分库/按列拆分表)和水平拆分(按行拆分到多个库/表)。分片策略有范围分片(简单但热点不均)、哈希分片(均匀但扩容难)、一致性哈希(均匀+易扩容)。常用中间件:ShardingSphere-JDBC(客户端)和 MyCat(代理)。核心挑战:分布式事务、跨库 JOIN、全局 ID。

初级理解

垂直拆分 vs 水平拆分

拆分方式操作示例解决的问题
垂直分库按业务拆库用户库、订单库、商品库业务解耦,独立扩容
垂直分表按列拆表用户主表(id,name)+ 用户详情表(id,address,bio)减少单表宽度,热门列和冷门列分离
水平分库按行拆到多个库user_db_0, user_db_1突破单库连接数和容量限制
水平分表按行拆到多个表order_0, order_1, order_2突破单表数据量瓶颈
# 什么时候需要分库分表? # 1. 单表数据量超过 500 万 ~ 2000 万(取决于行大小和查询复杂度) # 2. 单库连接数不够用 # 3. 磁盘 IO 成为瓶颈 # 优先考虑优化而非分库分表: # 1. 索引优化 + SQL 优化 # 2. 读写分离 # 3. 缓存(Redis) # 4. 历史数据归档
一句话总结:垂直拆业务/列,水平拆行;优先优化,实在不行再分库分表。

中级深入

分片策略对比

策略原理优点缺点
范围分片id 1~1000 在表0,1001~2000 在表1简单,易扩容热点不均(新数据集中)
哈希分片id % 4 决定表数据均匀扩容需全量迁移
一致性哈希哈希环 + 虚拟节点均匀 + 扩容只迁移部分实现复杂
地理位置分片按地区分库就近访问跨地区查询困难

ShardingSphere-JDBC 实战

# application.yml spring: shardingsphere: datasource: names: ds0, ds1 ds0: url: jdbc:mysql://localhost:3306/db0 ds1: url: jdbc:mysql://localhost:3306/db1 rules: sharding: tables: t_order: # 分库策略:user_id % 2 actual-data-nodes: ds$->{0..1}.t_order_$->{0..1} database-strategy: standard: sharding-column: user_id sharding-algorithm-name: db-inline # 分表策略:order_id % 2 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: tbl-inline sharding-algorithms: db-inline: type: INLINE props: algorithm-expression: ds$->{user_id % 2} tbl-inline: type: INLINE props: algorithm-expression: t_order_$->{order_id % 2}

全局 ID 生成方案

# 方案1:雪花算法(Snowflake) # 64位:1位符号 + 41位时间戳 + 10位机器ID + 12位序列号 # 优点:高性能、趋势递增、不依赖数据库 # 缺点:依赖时钟,时钟回拨可能重复 # 方案2:号段模式(美团 Leaf) # 从数据库批量获取 ID 号段,缓存在内存中 # 优点:高性能、趋势递增 # 缺点:依赖数据库 # 方案3:Redis 自增 INCR order_id # 原子自增 # 优点:简单 # 缺点:依赖 Redis,持久化可能丢数据
中级要点:哈希分片数据均匀但扩容难;ShardingSphere-JDBC 无代理性能好;雪花算法是常用全局 ID 方案。

高级拓展

分库分表后的挑战

挑战解决方案
分布式事务Seata AT/TCC、可靠消息最终一致性
跨库 JOIN字段冗余、全局表(广播表)、应用层组装
跨库分页/排序每个库查 TopN → 应用层归并排序
全局唯一 ID雪花算法、号段模式
数据迁移双写 + 历史数据迁移 + 灰度切换

数据迁移方案

# 平滑迁移步骤(不停机) # 1. 双写:新数据同时写旧库和新分片 # 2. 历史数据迁移:用定时任务分批迁移旧数据 # 3. 数据校验:对比新旧数据是否一致 # 4. 灰度切换:先切部分流量到新分片 # 5. 全量切换:确认无误后全量切到新分片 # 6. 下线旧库 # 工具推荐 # - ShardingSphere-Scaling:官方数据迁移工具 # - Canal + 自定义同步:基于 binlog 的增量同步

实战场景

场景:订单表水平分表(按用户 ID 哈希)

# 分 4 个库,每个库 4 张表,共 16 个分片 # 路由规则:user_id % 4 → 库,order_id % 4 → 表 # 查询:根据分片键查询(高效) SELECT * FROM t_order WHERE user_id = 100 AND order_id = 200; # → 路由到 ds0.t_order_0 # 查询:不带分片键(全分片扫描,低效) SELECT * FROM t_order WHERE status = 'paid'; # → 需要查所有 16 个分片,然后归并结果 # 最佳实践: # 1. 所有查询尽量带分片键 # 2. 非分片键查询走 ES 等搜索引擎 # 3. 广播表(字典表)每个库都存一份

面试模拟

面试官:什么时候需要分库分表?

你:单表数据量超过千万级、单库连接数不够、磁盘 IO 瓶颈时考虑。但优先做索引优化、SQL 优化、读写分离、缓存,实在不行再分库分表,因为分库分表会引入分布式事务、跨库 JOIN 等复杂性。

面试官:哈希分片扩容怎么办?

你:普通哈希(id % 4)扩容需要全量迁移。解决方案:1)一致性哈希——只迁移部分数据;2)预分片——一开始就分 32 个逻辑片,物理上先合并部署,扩容时迁移逻辑片;3)双写迁移——新数据双写,历史数据分批迁移,灰度切换。