数据库分库分表完全解析:如何拆分、路由策略与实战方案

深入详解分库分表的原因、分片策略(哈希/范围/时间)、路由算法、跨库查询、分布式ID、主从复制、迁移方案与常见问题

前言

“单表数据量太大怎么办?”

“什么时候该分库分表?”

“分片策略怎么选?哈希还是范围?”

“跨库查询怎么实现?”

“分库分表后主键怎么生成?”

这些问题困扰着很多开发者。今天我们就来全面解析分库分表,从为什么分,到怎么分,再到分后怎么用,系统性地掌握分库分表的核心知识。


一、为什么要分库分表

1.1 数据库性能瓶颈

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
┌─────────────────────────────────────────────────────────────────┐
│                    单库单表性能瓶颈                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │              MySQL单表性能曲线                           │   │
│   │                                                         │   │
│   │   性能                                                │   │
│   │   ▲                                                    │   │
│   │   │ ╲                                                 │   │
│   │   │   ╲                                               │   │
│   │   │    ╲                                              │   │
│   │   │     ╲_________________________________            │   │
│   │   │                                    ╲               │   │
│   │   │                                     ╲              │   │
│   │   └──────────────────────────────────────────────────▶│   │
│   │              0    500万   1000万   2000万  数据量     │   │
│   │                                                         │   │
│   │   说明:                                                │   │
│   │   • 1000万行以内,性能下降不明显                      │   │
│   │   • 超过1000万行,性能急剧下降                        │   │
│   │   • B+树层级增加,查询变慢                            │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   单库性能瓶颈:                                              │
│   ├── 最大QPS: 5000-10000 (普通服务器)                       │
│   ├── 最大TPS: 2000-5000                                    │
│   ├── 连接数上限: max_connections=10000                     │
│   └── 磁盘IO: SSD约5万IOPS                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 分库分表能解决什么

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
┌─────────────────────────────────────────────────────────────────┐
│                    分库分表解决的问题                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   问题1: 数据量太大                                    │   │
│   │   ├── 单表: 亿级数据查询慢                           │   │
│   │   ├── 单库: TB级数据存储难                          │   │
│   │   └── 解决: 分片存储,每片数据量可控                │   │
│   │                                                         │   │
│   │   问题2: 并发太高                                     │   │
│   │   ├── 单库QPS瓶颈: 1万                              │   │
│   │   ├── 连接数限制                                     │   │
│   │   └── 解决: 分库分散请求,多库并行处理              │   │
│   │                                                         │   │
│   │   问题3: 存储空间不足                                │   │
│   │   ├── 单机磁盘有限                                   │   │
│   │   ├── 单库容量上限                                  │   │
│   │   └── 解决: 分库存储,线性扩展容量                  │   │
│   │                                                         │   │
│   │   问题4: 可用性风险                                  │   │
│   │   ├── 单库故障影响全局                              │   │
│   │   └── 解决: 分库冗余,故障隔离                      │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.3 分库 vs 分表 vs 分区

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
┌─────────────────────────────────────────────────────────────────┐
│                    分库、分表、分区对比                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分区 (Partition) - 单库内部分表              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 逻辑一张表,物理多个分区                         │   │
│   │   ├── 对应用透明,无需修改代码                        │   │
│   │   ├── 存储在同一个数据库实例                          │   │
│   │   └── 无法解决连接数/并发问题                         │   │
│   │                                                         │   │
│   │   适用场景: 数据量大但并发不高                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分表 (Sharding) - 物理多表                  │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 物理多张表,数据分散存储                        │   │
│   │   ├── 需要应用层路由                                  │   │
│   │   ├── 可分库也可不分库                               │   │
│   │   └── 解决单表数据量问题                             │   │
│   │                                                         │   │
│   │   适用场景: 单表数据量过大                            │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分库 (Database Sharding) - 物理多库          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 物理多个数据库实例                             │   │
│   │   ├── 数据分散在不同数据库                          │   │
│   │   ├── 解决并发/连接数/容量问题                       │   │
│   │   └── 复杂度较高                                     │   │
│   │                                                         │   │
│   │   适用场景: 并发高或数据量极大                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   常见组合:                                                  │
│   ├── 分区: 单表分区,适合数据量大但并发不高               │
│   ├── 分表: 单库多表,适合单表数据量大                     │
│   ├── 分库分表: 多库多表,适合高并发大数据量              │
│   └── 先分区,不够再分库分表                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

二、分片策略

2.1 垂直拆分 vs 水平拆分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
┌─────────────────────────────────────────────────────────────────┐
│                    垂直拆分 vs 水平拆分                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              垂直拆分 (Vertical Sharding)                    │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   概念: 按业务/功能拆分                                │   │
│   │                                                         │   │
│   │   示例:                                               │   │
│   │   ┌─────────────────┐                                 │   │
│   │   │   用户中心库    │                                 │   │
│   │   │  (用户表)      │                                 │   │
│   │   └─────────────────┘                                 │   │
│   │   ┌─────────────────┐                                 │   │
│   │   │   订单中心库    │                                 │   │
│   │   │  (订单表)      │                                 │   │
│   │   └─────────────────┘                                 │   │
│   │   ┌─────────────────┐                                 │   │
│   │   │   商品中心库    │                                 │   │
│   │   │  (商品表)      │                                 │   │
│   │   └─────────────────┘                                 │   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 按业务模块划分                                  │   │
│   │   ├── 库之间无关联查询                               │   │
│   │   ├── 扩展相对简单                                    │   │
│   │   └── 可能存在热点库                                  │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              水平拆分 (Horizontal Sharding)                   │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   概念: 按数据拆分,每个库结构相同                     │   │
│   │                                                         │   │
│   │   示例:                                               │   │
│   │   ┌─────────────────┐  ┌─────────────────┐            │   │
│   │   │   订单库_0     │  │   订单库_1     │            │   │
│   │   │  (订单表_0)   │  │  (订单表_1)   │            │   │
│   │   │  user_id 0-9   │  │ user_id 10-19  │            │   │
│   │   └─────────────────┘  └─────────────────┘            │   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 按数据拆分,每个分片结构相同                    │   │
│   │   ├── 数据均匀分布                                    │   │
│   │   ├── 可解决单表数据量问题                           │   │
│   │   └── 跨库查询复杂                                   │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.2 垂直分库详解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
┌─────────────────────────────────────────────────────────────────┐
│                    垂直分库详解                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              电商系统垂直分库示例                           │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   拆分前 - 单体数据库:                                  │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   ┌─────────┐ ┌─────────┐ ┌─────────┐       │   │   │
│   │   │   │  用户   │ │  订单   │ │  商品   │       │   │   │
│   │   │   │  表    │ │   表   │ │   表   │       │   │   │
│   │   │   ├─────────┤ ├─────────┤ ├─────────┤       │   │   │
│   │   │   │ 用户信息│ │ 订单信息│ │ 商品信息│       │   │   │
│   │   │   │ 账号表 │ │ 订单明细│ │ 库存表 │       │   │   │
│   │   │   │ 地址表 │ │ 物流表 │ │ 分类表 │       │   │   │
│   │   │   └─────────┘ └─────────┘ └─────────┘       │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   拆分后 - 按业务拆分:                                  │   │
│   │   ┌───────────────┐  ┌───────────────┐  ┌─────────────┐│   │
│   │   │  用户中心库   │  │  订单中心库   │  │ 商品中心库  ││   │
│   │   │               │  │               │  │             ││   │
│   │   │ ┌─────────┐  │  │ ┌─────────┐  │  │ ┌─────────┐ ││   │
│   │   │ │用户主表 │  │  │ │订单主表 │  │  │ │商品主表 │ ││   │
│   │   │ ├─────────┤  │  │ ├─────────┤  │  │ ├─────────┤ ││   │
│   │   │ │用户扩展表│  │  │ │订单明细表│  │  │ │商品详情表│ ││   │
│   │   │ ├─────────┤  │  │ ├─────────┤  │  │ ├─────────┤ ││   │
│   │   │ │用户地址表│  │  │ │物流表  │  │  │ │分类表  │ ││   │
│   │   │ ├─────────┤  │  │ ├─────────┤  │  │ ├─────────┤ ││   │
│   │   │ │用户积分表│  │  │ │售后表  │  │  │ │品牌表  │ ││   │
│   │   │ └─────────┘  │  │ └─────────┘  │  │ └─────────┘ ││   │
│   │   └───────────────┘  └───────────────┘  └─────────────┘│   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   垂直分库步骤:                                               │
│   ├── 1. 梳理业务模块,识别核心业务                         │
│   ├── 2. 确定拆分边界,每个库独立业务                       │
│   ├── 3. 处理跨库关联 (应用层join/API)                      │
│   ├── 4. 配置数据源路由                                      │
│   └── 5. 逐步迁移,先迁移读请求再迁移写                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.3 水平分库分表详解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
┌─────────────────────────────────────────────────────────────────┐
│                    水平分库分表详解                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              水平分库分表架构                              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   拆分前:                                             │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │               order_db                          │   │   │
│   │   │   ┌─────────────────────────────────────────┐   │   │   │
│   │   │   │              orders                      │   │   │   │
│   │   │   │           (1亿条数据)                    │   │   │   │
│   │   │   └─────────────────────────────────────────┘   │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   拆分后:                                             │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   order_db_0          order_db_1          order_db_2 │ │
│   │   │   ┌───────────┐       ┌───────────┐       ┌─────────│   │
│   │   │   │orders_0 │       │orders_1 │       │orders_2│   │   │
│   │   │   │ 3300万   │       │ 3300万   │       │ 3400万  │   │   │
│   │   │   └───────────┘       └───────────┘       └─────────│   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   结果:                                                │   │
│   │   ├── 3个库,每个库3300-3400万行                      │   │
│   │   ├── 每个表控制在5000万以内                          │   │
│   │   └── 并发能力提升3倍                                 │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分片方案设计                                │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   分片数选择:                                          │   │
│   │   ├── 初期: 8或16个分片 (按数据量和增长预估)         │   │
│   │   ├── 中期: 32或64个分片                              │   │
│   │   └── 扩展: 支持在线扩容                              │   │
│   │                                                         │   │
│   │   计算公式:                                            │   │
│   │   分片数 = 数据总量 / 单表容量上限                    │   │
│   │                                                         │   │
│   │   示例:                                                │   │
│   │   ├── 数据总量: 10亿                                 │   │
│   │   ├── 单表上限: 1000万                               │   │
│   │   └── 分片数: 10亿 / 1000万 = 1000个分片            │   │
│   │                                                         │   │
│   │   实际考虑:                                            │   │
│   │   ├── 当前数据量                                     │   │
│   │   ├── 未来1-2年增长                                  │   │
│   │   ├── 单库承受QPS                                    │   │
│   │   └── 预留扩容空间 (一般1倍)                          │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

三、分片键与路由策略

3.1 分片键选择

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
┌─────────────────────────────────────────────────────────────────┐
│                    分片键选择原则                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分片键定义                                    │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   分片键 (Shard Key):                                   │   │
│   │   └── 用于将数据分散到不同分片的关键字段               │   │
│   │                                                         │   │
│   │   理想分片键特征:                                       │   │
│   │   ├── 查询频繁: 业务中高频使用的查询条件               │   │
│   │   ├── 数据均匀: 分布均匀,避免数据倾斜                  │   │
│   │   ├── 稳定不变: 不频繁修改                             │   │
│   │   └── 业务相关: 符合业务场景                           │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              常见分片键选择                              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │  业务场景        │  推荐分片键  │   原因         │   │   │
│   │   ├─────────────────────────────────────────────────┤   │   │
│   │   │  用户中心        │  user_id    │ 按用户隔离     │   │   │
│   │   │  订单中心        │  user_id    │ 查自己订单     │   │   │
│   │   │  商品中心        │  category_id│ 按分类查询     │   │   │
│   │   │  社交系统        │  user_id    │ 查看自己数据   │   │   │
│   │   │  日志系统        │  create_time│ 按时间查询     │   │   │
│   │   │  消息系统        │  receiver_id│ 查收件箱       │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   常见分片键:                                          │   │
│   │   ├── user_id: 用户维度                                │   │
│   │   ├── order_id: 订单维度                               │   │
│   │   ├── create_time: 时间维度                            │   │
│   │   └── region_id: 地域维度                              │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              分片键选择注意事项                          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   ❌ 不推荐:                                           │   │
│   │   ├── 主键ID自增: 写入热点集中                        │   │
│   │   ├── 状态字段: 数据倾斜严重                         │   │
│   │   └── 地区字段: 大城市数据过多                        │   │
│   │                                                         │   │
│   │   ✅ 推荐:                                             │   │
│   │   ├── 哈希分片: 均匀分布                              │   │
│   │   ├── 用户ID: 查询自己数据                           │   │
│   │   └── 时间字段: 时间范围查询                           │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.2 分片算法

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
┌─────────────────────────────────────────────────────────────────┐
│                    分片算法详解                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              算法1: 哈希分片 (Hash Sharding)               │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   原理: 分片键 % 分片数                                │   │
│   │                                                         │   │
│   │   示例: 8个分片                                        │   │
│   │   shard = hash(user_id) % 8                           │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   user_id=1001 → hash(1001)%8=5 → 分片5      │   │   │
│   │   │   user_id=1002 → hash(1002)%8=2 → 分片2      │   │   │
│   │   │   user_id=1003 → hash(1003)%8=7 → 分片7      │   │   │
│   │   │   user_id=1004 → hash(1004)%8=0 → 分片0      │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 数据分布均匀                                    │   │
│   │   缺点: 范围查询困难                                    │   │
│   │                                                         │   │
│   │   适用: 高并发写入,数据分布均匀的场景                  │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              算法2: 范围分片 (Range Sharding)              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   原理: 分片键值范围划分                               │   │
│   │                                                         │   │
│   │   示例: 按用户ID范围分片                               │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   分片0: user_id 0 - 999999                   │   │   │
│   │   │   分片1: user_id 1000000 - 1999999            │   │   │
│   │   │   分片2: user_id 2000000 - 2999999            │   │   │
│   │   │   分片3: user_id 3000000 - 3999999            │   │   │
│   │   │   ...                                           │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 范围查询友好                                    │   │
│   │   缺点: 可能产生热点分片 (新用户集中)                   │   │
│   │                                                         │   │
│   │   适用: 按时间/ID范围的查询场景                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              算法3: 一致性哈希 (Consistent Hashing)        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   原理: 哈希环 + 虚拟节点                             │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │          ┌────┐                                │   │   │
│   │   │          │Hash│                                │   │   │
│   │   │          │环  │                                │   │   │
│   │   │          └──┬─┘                                │   │   │
│   │   │             │                                  │   │   │
│   │   │    ┌────┬──┬─┴──┬────────┐                   │   │   │
│   │   │    │节点│  │    │        │                   │   │   │
│   │   │    │ A  │  │ B  │   C   │                   │   │   │
│   │   │    └────┘  └────┘        │                   │   │   │
│   │   │                             │                   │   │   │
│   │   │         顺时针找下一个节点                    │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 节点增减时数据迁移少                         │   │
│   │   缺点: 实现复杂,需要虚拟节点                       │   │
│   │                                                         │   │
│   │   适用: 需要动态扩容的场景                            │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              算法4: 查表法 (Map Table)                      │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   原理: 分片路由表                                     │   │
│   │                                                         │   │
│   │   示例:                                               │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   shard_id = route_table[hash(key) % 1000]    │   │   │
│   │   │                                                 │   │   │
│   │   │   路由表:                                        │   │   │
│   │   │   hash值范围      │ 分片号                      │   │   │
│   │   │   ─────────────────────────────────           │   │   │
│   │   │   0 - 124         │ 0                          │   │   │
│   │   │   125 - 249       │ 1                          │   │   │
│   │   │   250 - 374       │ 2                          │   │   │
│   │   │   ...                                            │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 灵活控制分布,支持灰度                        │   │
│   │   缺点: 多一次查询                                    │   │
│   │                                                         │   │
│   │   适用: 需要灵活路由控制的场景                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.3 路由计算示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
┌─────────────────────────────────────────────────────────────────┐
│                    路由计算示例                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              订单表分库分表路由计算                          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   分片配置:                                            │   │
│   │   ├── 分库数: 4 (order_db_0 ~ order_db_3)            │   │
│   │   ├── 分表数: 4 (orders_0 ~ orders_3)                 │   │
│   │   └── 分片键: user_id                                 │   │
│   │                                                         │   │
│   │   计算公式:                                            │   │
│   │   db_index = (user_id / 10000) % 4                    │   │
│   │   tb_index = user_id % 4                              │   │
│   │                                                         │   │
│   │   示例: user_id = 12345                               │   │
│   │   ├── db_index = (12345 / 10000) % 4 = 1             │   │
│   │   ├── tb_index = 12345 % 4 = 1                        │   │
│   │   └── 路由到: order_db_1.orders_1                    │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │              user_id=12345                      │   │   │
│   │   │                    │                            │   │   │
│   │   │                    ▼                            │   │   │
│   │   │         ┌───────────────────────┐              │   │   │
│   │   │         │   分片路由计算        │              │   │   │
│   │   │         │  db_idx=1, tb_idx=1   │              │   │   │
│   │   │         └───────────┬───────────┘              │   │   │
│   │   │                     │                          │   │   │
│   │   │     ┌───────────────┼───────────────┐          │   │   │
│   │   │     ▼               ▼               ▼          │   │   │
│   │   │  order_db_0    order_db_1    order_db_2    order_db_3 │
│   │   │  ┌──────┐     ┌──────┐      ┌──────┐     ┌──────┐│   │
│   │   │  │orders│     │orders│      │orders│     │orders││   │
│   │   │  │  _0  │     │  _1  │      │  _2  │     │  _3  ││   │
│   │   │  │_3    │     │_3    │      │_3    │     │_3    ││   │
│   │   │  └──────┘     └──────┘      └──────┘     └──────┘│   │
│   │   │                    ▲                          │   │   │
│   │   │                    │                          │   │   │
│   │   │              命中: order_db_1.orders_1        │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

四、分库分表中间件

4.1 中间件对比

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
┌─────────────────────────────────────────────────────────────────┐
│                    分库分表中间件对比                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   ┌──────────────┬──────────────┬──────────────┐        │   │
│   │   │   中间件     │    类型      │    代理模式   │        │   │
│   │   ├──────────────┼──────────────┼──────────────┤        │   │
│   │   │ ShardingSphere│   Apache    │ Proxy/客户端 │        │   │
│   │   │              │   顶级项目   │              │        │   │
│   │   ├──────────────┼──────────────┼──────────────┤        │   │
│   │   │   MyCat      │   开源      │   Proxy     │        │   │
│   │   │              │             │              │        │   │
│   │   ├──────────────┼──────────────┼──────────────┤        │   │
│   │   │   Vitess     │    Google   │   Proxy     │        │   │
│   │   │              │   开源      │              │        │   │
│   │   ├──────────────┼──────────────┼──────────────┤        │   │
│   │   │   DRDS       │    阿里云   │   Proxy     │        │   │
│   │   │              │   商业版    │              │        │   │
│   │   ├──────────────┼──────────────┼──────────────┤        │   │
│   │   │   TDDL       │    阿里     │   客户端    │        │   │
│   │   │              │   开源      │              │        │   │
│   │   └──────────────┴──────────────┴──────────────┘        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              客户端模式 vs 代理模式                          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │              客户端模式 (ShardingJDBC)              │   │   │
│   │   │                                                 │   │   │
│   │   │   应用 ──────────▶ MySQL                       │   │   │
│   │   │     │                                         │   │   │
│   │   │     │ ShardingJDBC                           │   │   │
│   │   │     │ (应用内嵌)                               │   │   │
│   │   │     │                                         │   │   │
│   │   │   优点:                                        │   │   │
│   │   │   ├── 性能高 (无网络转发)                      │   │   │
│   │   │   ├── 部署简单                                │   │   │
│   │   │   └── 运维成本低                              │   │   │
│   │   │                                             │   │   │
│   │   │   缺点:                                        │   │   │
│   │   │   ├── 需要修改代码引入依赖                   │   │   │
│   │   │   └── 多语言支持需分别实现                   │   │   │
│   │   │                                             │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │              代理模式 (ShardingSphere-Proxy)       │   │   │
│   │   │                                                 │   │   │
│   │   │   应用 ──────────▶ Proxy ──────────▶ MySQL    │   │   │
│   │   │                                 │              │   │   │
│   │   │                          (独立部署)              │   │   │
│   │   │                                             │   │   │
│   │   │   优点:                                        │   │   │
│   │   │   ├── 透明接入,无需改代码                   │   │   │
│   │   │   ├── 多语言支持                             │   │   │
│   │   │   └── 统一管理                               │   │   │
│   │   │                                             │   │   │
│   │   │   缺点:                                        │   │   │
│   │   │   ├── 多一跳,有性能损耗                    │   │   │
│   │   │   ├── 需要额外部署运维                      │   │   │
│   │   │   └── 引入复杂度                            │   │   │
│   │   │                                             │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4.2 ShardingSphere配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# ShardingSphere 分库分表配置
schema:
  name: sharding_db
  
  dataSources:
    # 配置4个数据源
    ds_0:
      dataSourceClassName: com.zaxxer.hikari.HikariDataSource
      driverClassName: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://192.168.1.10:3306/ds_0?useUnicode=true
      username: root
      password: root123
      
    ds_1:
      dataSourceClassName: com.zaxxer.hikari.HikariDataSource
      driverClassName: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://192.168.1.11:3306/ds_1?useUnicode=true
      username: root
      password: root123
      
    ds_2:
      dataSourceClassName: com.zaxxer.hikari.HikariDataSource
      driverClassName: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://192.168.1.12:3306/ds_2?useUnicode=true
      username: root
      password: root123
      
    ds_3:
      dataSourceClassName: com.zaxxer.hikari.HikariDataSource
      driverClassName: com.mysql.cj.jdbc.Driver
      jdbcUrl: jdbc:mysql://192.168.1.13:3306/ds_3?useUnicode=true
      username: root
      password: root123

# 分片规则配置
rules:
  - !SHARDING
    tables:
      # 订单表分库分表
      t_order:
        actualDataNodes: ds_${0..3}.t_order_${0..3}
        # 分片策略
        databaseStrategy:
          standard:
            shardingColumn: user_id
            shardingAlgorithmName: database_inline
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: table_inline
        
        # 主键生成
        keyGenerateStrategy:
          column: order_id
          keyGeneratorName: snowflake
    
    # 分片算法定义
    shardingAlgorithms:
      # 库分片算法
      database_inline:
        type: INLINE
        props:
          algorithm-expression: ds_${Math.floor(user_id % 10000 / 2500)}
          # user_id 0-2499 → ds_0, 2500-4999 → ds_1, ...
      
      # 表分片算法
      table_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${order_id % 4}
    
    # 主键生成器
    keyGenerators:
      snowflake:
        type: SNOWFLAKE
        props:
          worker-id: 1

4.3 TDDL配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// TDDL 分库分表配置
// 应用配置
@ShardBy("userId")
public interface OrderDAO {
    
    @Sql("SELECT * FROM orders WHERE user_id = ? AND status = ?")
    List<Order> selectByUserIdAndStatus(@Param("userId") Long userId, 
                                         @Param("status") Integer status);
}

// 分片规则配置
public class TDDLRuleConfig {
    
    // 分库数量
    private int dbCount = 4;
    
    // 分表数量
    private int tableCount = 4;
    
    // 分片函数
    public int calculateDbIndex(Long userId) {
        // 按用户ID分库
        return (int) (userId % dbCount);
    }
    
    public int calculateTableIndex(Long orderId) {
        // 按订单ID分表
        return (int) (orderId % tableCount);
    }
}

五、分布式ID生成

5.1 主键生成方案对比

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
┌─────────────────────────────────────────────────────────────────┐
│                    主键生成方案对比                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              UUID                                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   优点:                                                │   │
│   │   ├── 本地生成,无网络开销                             │   │
│   │   └── 全球唯一                                         │   │
│   │                                                         │   │
│   │   缺点:                                                │   │
│   │   ├── 128位太长,存储浪费                             │   │
│   │   ├── 无序,插入性能差                                │   │
│   │   └── 不可读                                           │   │
│   │                                                         │   │
│   │   适用: 不推荐作为数据库主键                           │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              数据库自增                                  │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   优点:                                                │   │
│   │   ├── 有序,插入性能好                                │   │
│   │   └── 简单                                             │   │
│   │                                                         │   │
│   │   缺点:                                                │   │
│   │   ├── 强依赖数据库                                    │   │
│   │   ├── 分库分表后难以保证唯一                         │   │
│   │   └── 单点性能瓶颈                                    │   │
│   │                                                         │   │
│   │   适用: 单库单表场景                                  │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              Snowflake雪花算法                            │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   64位 = 1位符号 + 41位时间戳 + 10位机器ID + 12位序列号   │   │
│   │   ┌───┬─────────────────────────┬──────────┬──────────┐│   │
│   │   │ 0 │    000001011010010010...│ 00000001 │ 00000001 ││   │
│   │   └───┴─────────────────────────┴──────────┴──────────┘│   │
│   │     │           时间戳(ms)           │ 机器ID  │ 序列号 ││   │
│   │     1位                       41位          10位     12位  │   │
│   │                                                         │   │
│   │   优点:                                                │   │
│   │   ├── 有序,趋势递增                                  │   │
│   │   ├── 不依赖数据库                                    │   │
│   │   ├── 性能高,本地生成                               │   │
│   │   └── 趋势递增,对B+树友好                           │   │
│   │                                                         │   │
│   │   缺点:                                                │   │
│   │   ├── 依赖系统时钟                                   │   │
│   │   └── 强依赖机器ID分配                               │   │
│   │                                                         │   │
│   │   适用: 分库分表主键,推荐使用                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              数据库号段模式                              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   原理: 批量从数据库获取ID号段,本地分配               │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   本地号段: [1000 - 2000]                       │   │   │
│   │   │        ↓                                        │   │   │
│   │   │   本地分配: 1001, 1002, 1003...                │   │   │
│   │   │        ↓                                        │   │   │
│   │   │   分配完后再从数据库获取新号段                   │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 不依赖时间,可批量获取                        │   │
│   │   缺点: 依赖数据库,需要处理号段分配                  │   │
│   │                                                         │   │
│   │   适用: 需要全局有序ID的场景                         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

5.2 Snowflake实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
 * Snowflake 雪花算法实现
 */
public class SnowflakeIdGenerator {
    
    // 时间戳起始时间 (2020-01-01)
    private final long EPOCH = 1577836800000L;
    
    // 机器ID位数
    private final long WORKER_ID_BITS = 5L;
    // 数据中心ID位数
    private final long DATACENTER_ID_BITS = 5L;
    // 序列号位数
    private final long SEQUENCE_BITS = 12L;
    
    // 最大值
    private final long maxWorkerId = ~(-1L << WORKER_ID_BITS);
    private final long maxDatacenterId = ~(-1L << DATACENTER_ID_BITS);
    
    // 左移位数
    private final long workerIdShift = SEQUENCE_BITS;
    private final long datacenterIdShift = SEQUENCE_BITS + WORKER_ID_BITS;
    private final long timestampLeftShift = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS;
    
    // 序列号掩码
    private final long sequenceMask = ~(-1L << SEQUENCE_BITS);
    
    // 基础属性
    private long workerId;
    private long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException("Worker ID 超出范围");
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID 超出范围");
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    
    /**
     * 生成下一个ID
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        
        // 时钟回拨检测
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨,拒绝生成ID");
        }
        
        // 同一毫秒内序列号递增
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            // 序列号用完,等待下一毫秒
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 新的毫秒,序列号归零
            sequence = 0L;
        }
        
        lastTimestamp = timestamp;
        
        // 组装ID
        return ((timestamp - EPOCH) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift)
                | sequence;
    }
    
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
    
    private long timeGen() {
        return System.currentTimeMillis();
    }
    
    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
        
        for (int i = 0; i < 10; i++) {
            long id = idGenerator.nextId();
            System.out.println("生成的ID: " + id);
            System.out.println("二进制: " + Long.toBinaryString(id));
        }
    }
}

六、跨库查询处理

6.1 跨库查询场景

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
┌─────────────────────────────────────────────────────────────────┐
│                    跨库查询场景与解决方案                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              场景1: 跨分片排序分页                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   问题: 查第100页,每页10条                              │   │
│   │                                                         │   │
│   │   解决: 两次查询法                                      │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   Step 1: 各分片查询,返回更多数据               │   │   │
│   │   │   SELECT * FROM t_order WHERE user_id IN (...)   │   │   │
│   │   │          ORDER BY create_time DESC LIMIT 1050    │   │   │
│   │   │                                                 │   │   │
│   │   │   Step 2: 应用层合并排序                         │   │   │
│   │   │   合并所有分片结果 → 内存排序 → 返回第100页     │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   注意: 深度分页性能差,建议限制最大页码               │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              场景2: 跨分片聚合统计                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   问题: 计算所有用户的订单总额                          │   │
│   │                                                         │   │
│   │   解决: 各分片计算,应用层汇总                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   Step 1: 各分片执行聚合                        │   │   │
│   │   │   SELECT SUM(amount) FROM t_order               │   │   │
│   │   │          WHERE create_time >= '2024-01-01'      │   │   │
│   │   │                                                 │   │   │
│   │   │   Step 2: 应用层汇总                             │   │   │
│   │   │   total = SUM(分片1结果 + 分片2结果 + ...)      │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   支持的聚合: SUM/AVG/MIN/MAX/COUNT                  │   │
│   │   不支持: 中位数/百分位数/标准差 (需全量数据)         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              场景3: 跨分片关联查询                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   问题: 订单表和用户表JOIN                             │   │
│   │                                                         │   │
│   │   解决方案:                                            │   │
│   │   ├── 方案1: 字段冗余                                  │   │
│   │   │   订单表冗余用户姓名,查询时无需JOIN              │   │
│   │   │                                                │   │   │
│   │   ├── 方案2: 同步数据                                  │   │   │
│   │   │   将用户信息同步到订单表所在分片                  │   │
│   │   │                                                │   │   │
│   │   └── 方案3: 业务层面拆分                             │   │
│   │       先查用户 → 再查订单(按用户) → 应用层组装         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6.2 广播表与字典表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
┌─────────────────────────────────────────────────────────────────┐
│                    广播表与全局表                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              广播表 (Broadcast Table)                      │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   定义: 数据量小且变动少的表                            │   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 每个分片都存储一份完整数据                      │   │
│   │   ├── 写入时同步到所有分片                            │   │
│   │   ├── 读取时从本地读取                                │   │
│   │   └── 无需跨库JOIN                                    │   │
│   │                                                         │   │
│   │   适用:                                                │   │
│   │   ├── 地区表                                            │   │
│   │   ├── 配置表                                            │   │
│   │   └── 字典表                                            │   │
│   │                                                         │   │
│   │   示例: 地区表                                          │   │
│   │   ┌───────────┐  ┌───────────┐  ┌───────────┐        │   │
│   │   │ ds_0      │  │ ds_1      │  │ ds_2      │        │   │
│   │   │ ┌───────┐ │  │ ┌───────┐ │  │ ┌───────┐ │        │   │
│   │   │ │ region │ │  │ │ region │ │  │ │ region │ │        │   │
│   │   │ └───────┘ │  │ └───────┘ │  │ └───────┘ │        │   │
│   │   └───────────┘  └───────────┘  └───────────┘        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              全局表 (Global Table)                         │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   定义: 需要跨分片关联查询的表                          │   │
│   │                                                         │   │
│   │   特点:                                                │   │
│   │   ├── 所有分片都有完整数据                            │   │
│   │   ├── 同步方式保证一致性                              │   │
│   │   └── 用于分片键无法确定时的JOIN                     │   │
│   │                                                         │   │
│   │   注意: 数据量大时不适用                               │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              关系表设计建议                                │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   最佳实践:                                            │   │
│   │   ├── 避免跨分片JOIN                                  │   │
│   │   ├── 相关表采用相同分片键                            │   │
│   │   ├── 小表使用广播表                                   │   │
│   │   ├── 大表拆分到多个分片                              │   │
│   │   └── 必要时接受数据冗余                              │   │
│   │                                                         │   │
│   │   示例: 订单表和订单明细表                            │   │
│   │   ├── 相同分片键: order_id (或 user_id)              │   │
│   │   └── 同一分片内JOIN,性能好                         │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

七、主从复制与高可用

7.1 读写分离架构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌─────────────────────────────────────────────────────────────────┐
│                    读写分离架构                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │              应用层                                       │   │
│   │                  │                                        │   │
│   │         ┌────────┴────────┐                            │   │
│   │         │                 │                             │   │
│   │         ▼                 ▼                             │   │
│   │   ┌──────────┐      ┌──────────┐                      │   │
│   │   │ 写数据源 │      │ 读数据源 │                      │   │
│   │   │(主库)   │      │(从库)   │                      │   │
│   │   └────┬─────┘      └────┬─────┘                      │   │
│   │        │                 │                               │   │
│   │        └────────┬────────┘                               │   │
│   │                 │                                        │   │
│   │                 ▼                                        │   │
│   │          ┌──────────────┐                              │   │
│   │          │  ShardingSphere │                           │   │
│   │          │  (读写分离)    │                           │   │
│   │          └──────────────┘                              │   │
│   │                 │                                        │   │
│   │      ┌─────────┴─────────┐                             │   │
│   │      ▼                   ▼                             │   │
│   │  ┌────────┐         ┌────────┐                      │   │
│   │  │ Master │◀─复制──│ Slave1 │                      │   │
│   │  │       │         │       │                      │   │
│   │  └────────┘         └────────┘                      │   │
│   │                        ▲                             │   │
│   │                        │                             │   │
│   │                   ┌────────┐                      │   │
│   │                   │ Slave2 │                      │   │
│   │                   │       │                      │   │
│   │                   └────────┘                      │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   复制延迟问题处理:                                            │
│   ├── 强制读主库: 写后必须读的场景                           │
│   ├── 延迟检测: GTID追踪延迟                               │
│   └── 缓存记录: 写后一段时间内读主库                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.2 分片高可用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌─────────────────────────────────────────────────────────────────┐
│                    分片高可用架构                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │         客户端 (应用层 + ShardingJDBC)           │   │   │
│   │   └─────────────────────────┬───────────────────────────┘   │   │
│   │                             │                               │   │
│   │                             │ 心跳检测                      │   │
│   │                             ▼                               │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │  ┌─────────────┐   ┌─────────────┐             │   │   │
│   │   │  │  ZooKeeper │   │   Nacos    │             │   │   │
│   │   │  │  (注册中心) │   │ (注册中心) │             │   │   │
│   │   │  └──────┬──────┘   └──────┬──────┘             │   │   │
│   │   │         │                 │                      │   │   │
│   │   │         └────────┬────────┘                      │   │   │
│   │   │                  │                               │   │   │
│   │   │     ┌───────────┼───────────┐                   │   │   │
│   │   │     │           │           │                    │   │   │
│   │   │     ▼           ▼           ▼                    │   │   │
│   │   │  ┌────────┐ ┌────────┐ ┌────────┐              │   │   │
│   │   │  │ ds_0   │ │ ds_1   │ │ ds_2   │              │   │   │
│   │   │  │主从集群│ │主从集群│ │主从集群│              │   │   │
│   │   │  └────────┘ └────────┘ └────────┘              │   │   │
│   │   │     ▲           ▲           ▲                    │   │   │
│   │   │     │           │           │                    │   │   │
│   │   │  ┌────────┐ ┌────────┐ ┌────────┐              │   │   │
│   │   │  │ Slave1 │ │ Slave1 │ │ Slave1 │              │   │   │
│   │   │  │ Slave2 │ │ Slave2 │ │ Slave2 │              │   │   │
│   │   │  └────────┘ └────────┘ └────────┘              │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   故障切换:                                           │   │
│   │   ├── 主库故障 → 从库自动升级为主库                 │   │
│   │   ├── 应用层感知 → 切换数据源                       │   │
│   │   └── 切换时间: <30秒                                │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

八、数据迁移方案

8.1 迁移策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
┌─────────────────────────────────────────────────────────────────┐
│                    分库分表迁移策略                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              迁移原则                                    │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   ├── 风险可控: 灰度发布,逐步迁移                     │   │
│   │   ├── 停机时间: 越短越好,最好不停服                   │   │
│   │   ├── 数据一致性: 迁移前后数据一致                     │   │
│   │   └── 可回滚: 迁移失败可快速回退                       │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              方案1: 停机迁移                              │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   步骤:                                                │   │
│   │   1. 通知用户停机维护                                  │   │
│   │   2. 停止应用写入                                      │   │
│   │   3. 导出全量数据                                      │   │
│   │   4. 数据清洗和转换                                    │   │
│   │   5. 导入新分片库                                      │   │
│   │   6. 验证数据完整性                                    │   │
│   │   7. 切换应用配置                                      │   │
│   │   8. 启动应用                                          │   │
│   │                                                         │   │
│   │   适用: 数据量小,允许停机的场景                      │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              方案2: 双写迁移 (推荐)                       │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   阶段1: 初始化                                  │   │   │
│   │   │   ├── 部署分库分表集群                          │   │   │
│   │   │   └── 历史数据全量迁移                         │   │   │
│   │   │                                                 │   │   │
│   │   │   阶段2: 双写                                    │   │   │
│   │   │   ├── 老库 + 新库双写                          │   │   │
│   │   │   └── 记录双写期间增量数据                     │   │   │
│   │   │                                                 │   │   │
│   │   │   阶段3: 数据校验                                │   │   │
│   │   │   ├── 对比两库数据一致性                       │   │   │
│   │   │   └── 修复差异数据                              │   │   │
│   │   │                                                 │   │   │
│   │   │   阶段4: 流量切换                                │   │   │
│   │   │   ├── 读流量先切换到新库                       │   │   │
│   │   │   ├── 验证新库读正确                           │   │   │
│   │   │   └── 逐步切换写流量                           │   │   │
│   │   │                                                 │   │   │
│   │   │   阶段5: 下线老库                                │   │   │
│   │   │   └── 确认无误后停止双写                       │   │   │
│   │   │                                                 │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   适用: 生产环境,不允许停机的场景                    │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              方案3: CDC变更数据捕获                      │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   工具: Debezium / Canal / Maxwell                     │   │
│   │                                                         │   │
│   │   ┌─────────────────────────────────────────────────┐   │   │
│   │   │                                                 │   │   │
│   │   │   MySQL ──▶ Canal ──▶ Kafka ──▶ 消费 ──▶ 新库│   │   │
│   │   │                   │               │             │   │   │
│   │   │                   │          数据同步            │   │   │
│   │   │                   │                             │   │   │
│   │   └─────────────────────────────────────────────────┘   │   │
│   │                                                         │   │
│   │   优点: 实时同步,不丢数据                             │   │
│   │   缺点: 架构复杂,需要处理冲突                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

8.2 数据校验

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-- 数据校验脚本示例
-- 1. 统计校验
SELECT 
    COUNT(*) as total_count,
    COUNT(DISTINCT user_id) as user_count
FROM t_order;

-- 2. 抽样校验 (随机抽取100条对比)
SELECT * FROM t_order 
ORDER BY RAND() 
LIMIT 100;

-- 3. 增量数据校验 (基于时间戳)
SELECT COUNT(*) as new_count
FROM t_order 
WHERE create_time > '2024-01-01 00:00:00';

-- 4. 跨分片数据校验
-- 分片0
SELECT COUNT(*) FROM t_order_0;
-- 分片1
SELECT COUNT(*) FROM t_order_1;
-- 分片2
SELECT COUNT(*) FROM t_order_2;
-- 分片3
SELECT COUNT(*) FROM t_order_3;

-- 汇总
SELECT SUM(cnt) as total FROM (
    SELECT COUNT(*) as cnt FROM t_order_0
    UNION ALL
    SELECT COUNT(*) as cnt FROM t_order_1
    UNION ALL
    SELECT COUNT(*) as cnt FROM t_order_2
    UNION ALL
    SELECT COUNT(*) as cnt FROM t_order_3
) t;

九、实战配置示例

9.1 订单表分库分表实战

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
-- 创建分库脚本
-- 库: order_db_0, order_db_1, order_db_2, order_db_3

-- 每个库执行
CREATE DATABASE order_db_0 DEFAULT CHARSET utf8mb4;
CREATE DATABASE order_db_1 DEFAULT CHARSET utf8mb4;
CREATE DATABASE order_db_2 DEFAULT CHARSET utf8mb4;
CREATE DATABASE order_db_3 DEFAULT CHARSET utf8mb4;

-- 订单表结构
CREATE TABLE orders_0 (
    order_id BIGINT PRIMARY KEY COMMENT '订单ID',
    user_id BIGINT NOT NULL COMMENT '用户ID',
    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
    total_amount DECIMAL(12,2) NOT NULL COMMENT '订单金额',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_create_time (create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

-- 创建其他分表 (orders_1, orders_2, orders_3 结构相同)

-- 订单明细表 (与订单同分片键)
CREATE TABLE order_items_0 (
    item_id BIGINT PRIMARY KEY COMMENT '明细ID',
    order_id BIGINT NOT NULL COMMENT '订单ID',
    product_id BIGINT NOT NULL COMMENT '商品ID',
    product_name VARCHAR(200) NOT NULL COMMENT '商品名称',
    price DECIMAL(12,2) NOT NULL COMMENT '单价',
    quantity INT NOT NULL COMMENT '数量',
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_order_id (order_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';

9.2 Java代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// ShardingSphere 配置
@Configuration
public class ShardingConfig {
    
    @Bean
    public DataSource dataSource() {
        ShardingRuleConfiguration config = new ShardingRuleConfiguration();
        
        // 配置分片表
        config.getTables().add(createOrderTableRule());
        
        // 配置绑定表 (同分片键的表)
        config.getBindingTableGroups().add("t_order,t_order_item");
        
        // 配置广播表
        config.getBroadcastTables().add("t_region");
        
        // 配置默认数据库策略
        config.setDefaultDatabaseShardingStrategy(
            new StandardShardingStrategyConfiguration("user_id", "databaseShardingAlgorithm")
        );
        
        // 配置默认表策略
        config.setDefaultTableShardingStrategy(
            new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm")
        );
        
        DataSource dataSource = ShardingDataSourceFactory.createDataSource(
            createDataSourceMap(), config, new Properties()
        );
        
        return dataSource;
    }
    
    private Map<String, DataSource> createDataSourceMap() {
        Map<String, DataSource> map = new HashMap<>();
        // 配置4个数据源
        for (int i = 0; i < 4; i++) {
            map.put("ds_" + i, createDataSource("jdbc:mysql://host" + i + ":3306/ds_" + i));
        }
        return map;
    }
    
    private TableRuleConfiguration createOrderTableRule() {
        TableRuleConfiguration config = new TableRuleConfiguration();
        config.setLogicTable("t_order");
        // 实际表节点
        config.setActualDataNodes("ds_${0..3}.t_order_${0..3}");
        // 主键生成
        config.setKeyGeneratorConfig(new KeyGeneratorConfiguration("snowfall", "order_id"));
        return config;
    }
}

// 使用示例
@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Override
    public Long createOrder(Order order) {
        // 主键由ShardingSphere自动生成 (Snowflake)
        orderMapper.insert(order);
        return order.getOrderId();
    }
    
    @Override
    public List<Order> getOrdersByUserId(Long userId) {
        // 路由到特定分片,无需跨分片查询
        return orderMapper.selectByUserId(userId);
    }
    
    @Override
    public PageInfo<Order> getOrdersPage(Long userId, int pageNum, int pageSize) {
        // 分页查询
        return orderMapper.selectByUserIdWithPage(userId, pageNum, pageSize);
    }
}

十、常见问题与解决方案

10.1 分库分表常见问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
┌─────────────────────────────────────────────────────────────────┐
│                    常见问题与解决方案                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              问题1: 深分页性能差                          │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   现象: 查询第1000页,极慢                              │   │
│   │                                                         │   │
│   │   原因: 需要扫描大量分片数据                            │   │
│   │                                                         │   │
│   │   解决:                                                │   │
│   │   ├── 限制最大页码: 最多查前100页                     │   │
│   │   ├── 游标分页: 基于上一页最大ID                      │   │
│   │   ├── 记录分页: 用ES存储,MySQL存数据                 │   │
│   │   └── 禁止跳页: 只提供上一页下一页                    │   │
│   │                                                         │   │
│   │   游标分页示例:                                        │   │
│   │   SELECT * FROM orders                                  │   │
│   │   WHERE user_id = ?                                    │   │
│   │   AND order_id < #{lastOrderId}                        │   │
│   │   ORDER BY order_id DESC                               │   │
│   │   LIMIT 20;                                            │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              问题2: 分片键无法修改                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   现象: 需要按新字段分片,旧数据如何处理                │   │
│   │                                                         │   │
│   │   解决:                                                │   │
│   │   ├── 双写: 旧分片+新分片同时写入                    │   │
│   │   ├── 数据迁移: 异步迁移历史数据                     │   │
│   │   ├── 灰度切换: 逐步切流量到新分片                   │   │
│   │   └── 清理: 确认无误后删除旧分片数据                │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              问题3: 分布式事务问题                      │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   现象: 跨分片操作无法保证原子性                       │   │
│   │                                                         │   │
│   │   解决:                                                │   │
│   │   ├── 避免跨分片事务                                  │   │
│   │   ├── 最终一致性: 异步补偿                            │   │
│   │   ├── TCC模式: Try-Confirm-Cancel                    │   │
│   │   ├── XA事务: 两阶段提交 (性能损耗大)               │   │
│   │   └── Saga模式: 链式调用+补偿                        │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              问题4: 数据热点问题                        │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   现象: 某些分片数据量特别大                          │   │
│   │                                                         │   │
│   │   原因: 分片键分布不均匀或热点用户集中                │   │
│   │                                                         │   │
│   │   解决:                                                │   │
│   │   ├── 优化分片键: 使用哈希+随机                      │   │
│   │   ├── 增加分片数: 扩容                               │   │
│   │   ├── 热数据分离: 热点数据独立分片                   │   │
│   │   └── 写入负载均衡: 多分片键组合                     │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │              问题5: 跨分片JOIN                         │   │
│   ├─────────────────────────────────────────────────────────┤   │
│   │                                                         │   │
│   │   现象: 需要关联不同分片的数据                          │   │
│   │                                                         │   │
│   │   解决:                                                │   │
│   │   ├── 字段冗余: 常用字段冗余存储                     │   │
│   │   ├── 多次查询: 分开查询,应用层JOIN                 │   │
│   │   ├── 绑定表: 同分片键的表放一起                     │   │
│   │   ├── 全局表: 小表广播到所有分片                     │   │
│   │   └── ES/搜索库: 复杂查询走搜索库                   │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

十一、总结

11.1 分库分表决策流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
┌─────────────────────────────────────────────────────────────────┐
│                    分库分表决策流程                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────────────────────┐   │
│   │                                                         │   │
│   │   Step 1: 是否需要分库分表?                           │   │
│   │   │                                                    │   │
│   │   ├── 单表数据 < 1000万 → 暂不需要                   │   │
│   │   ├── 单表数据 1000-5000万 → 先考虑分区              │   │
│   │   └── 单表数据 > 5000万 → 需要分库分表               │   │
│   │   │                                                    │   │
│   │   ▼                                                    │   │
│   │   Step 2: 选择拆分方式                                 │   │
│   │   │                                                    │   │
│   │   ├── 垂直拆分: 按业务模块拆分                       │   │
│   │   └── 水平拆分: 按数据拆分                           │   │
│   │   │                                                    │   │
│   │   ▼                                                    │   │
│   │   Step 3: 选择分片键                                   │   │
│   │   │                                                    │   │
│   │   ├── 高频查询字段                                    │   │
│   │   ├── 数据分布均匀                                    │   │
│   │   └── 稳定不变                                        │   │
│   │   │                                                    │   │
│   │   ▼                                                    │   │
│   │   Step 4: 选择分片算法                                 │   │
│   │   │                                                    │   │
│   │   ├── 哈希分片: 均匀分布                             │   │
│   │   ├── 范围分片: 范围查询友好                         │   │
│   │   └── 一致性哈希: 方便扩容                           │   │
│   │   │                                                    │   │
│   │   ▼                                                    │   │
│   │   Step 5: 选择中间件                                   │   │
│   │   │                                                    │   │
│   │   ├── ShardingSphere (推荐)                          │   │
│   │   ├── MyCat (传统项目)                                │   │
│   │   └── DRDS/TDDL (阿里体系)                           │   │
│   │                                                         │   │
│   └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

11.2 关键知识点速查

维度 选项 适用场景
拆分方式 垂直拆分 按业务模块,数据量不均
拆分方式 水平拆分 数据量大,需线性扩展
分片键 user_id 用户维度查询
分片键 order_id 订单维度查询
分片键 create_time 时间范围查询
分片算法 哈希 写入均匀,随机查询
分片算法 范围 范围查询,时间序列
中间件 ShardingSphere 通用方案
中间件 TDDL 阿里体系
ID生成 Snowflake 推荐方案
ID生成 UUID 不推荐

11.3 最佳实践

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────────┐
│                    分库分表最佳实践                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ✅ 应该做的:                                                 │
│   ├── 选择高频查询字段作为分片键                               │
│   ├── 同分片键的表绑定在一起                                  │
│   ├── 小表广播到所有分片                                      │
│   ├── 主键使用分布式ID生成器                                  │
│   ├── 预留分片数量 (1-2倍)                                   │
│   ├── 异步迁移数据,停机时间短                                │
│   └── 数据校验后再切换                                        │
│                                                                 │
│   ❌ 不应该做的:                                               │
│   ├── 不要用自增ID作为分片键                                  │
│   ├── 不要跨分片JOIN                                          │
│   ├── 不要深度分页                                            │
│   ├── 不要分片后还想事务操作                                  │
│   └── 不要一次性迁移大量数据                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

希望这篇文章能帮助你全面理解分库分表的技术细节。分库分表是一把双刃剑,在解决性能问题的同时也会引入复杂度,要谨慎评估后再做决定。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计