问题
什么是分库分表?
答案
1. 核心概念
分库分表是一种数据库水平扩展方案,通过将单个数据库或表的数据拆分到多个数据库或表中,来解决单库单表的性能瓶颈和存储容量限制问题。
分为两个维度:
- 分库(Database Sharding):将数据分散到多个数据库实例中,分摊单库的并发压力和连接数
- 分表(Table Sharding):将单表数据分散到多个表中,降低单表数据量,提升查询性能
2. 分库分表的分类
2.1 垂直拆分
- 垂直分库:按业务模块将不同的表拆分到不同的数据库中
- 例如:将用户库、订单库、商品库拆分为独立的数据库
- 优点:业务隔离,降低耦合,便于维护
- 垂直分表:将表中的字段拆分到多个表中
- 例如:将用户表拆分为用户基本信息表和用户扩展信息表
- 优点:减少单表字段数,适合大字段或低频字段的分离
2.2 水平拆分
- 水平分库:将同一张表的数据按某种规则分散到多个数据库中
- 例如:按用户ID范围或哈希值分配到不同的数据库
- 水平分表:将同一张表的数据按某种规则分散到多个表中
- 例如:order_0, order_1, order_2…
- 优点:降低单表数据量,提升查询和写入性能
3. 为什么需要分库分表
| 问题类型 | 说明 | 解决方案 |
|---|---|---|
| 单表数据量过大 | 千万级数据导致查询变慢,索引失效 | 水平分表 |
| 并发压力大 | 单库连接数有限,CPU/IO成为瓶颈 | 水平分库 |
| 磁盘容量不足 | 单机存储空间有限 | 水平分库 |
| 业务耦合严重 | 不同业务共用一个库,相互影响 | 垂直分库 |
4. 示例场景
假设有一个订单表 order,数据量达到1亿条:
-- 原始单表结构
CREATE TABLE order (
order_id BIGINT PRIMARY KEY,
user_id BIGINT,
product_id BIGINT,
amount DECIMAL(10,2),
create_time DATETIME
);
水平分表方案:按 order_id 取模拆分为16张表
// 分表路由算法
public String getTableName(Long orderId) {
int tableIndex = (int) (orderId % 16);
return "order_" + tableIndex; // order_0 ~ order_15
}
水平分库方案:按 user_id 哈希分配到4个数据库
// 分库路由算法
public String getDatabaseName(Long userId) {
int dbIndex = Math.abs(userId.hashCode() % 4);
return "db_" + dbIndex; // db_0 ~ db_3
}
5. 核心要点总结
- 分库分表是解决单库单表性能瓶颈的有效手段,主要应对高并发和大数据量场景
- 垂直拆分关注业务隔离,水平拆分关注数据量和并发分摊
- 分库解决并发和存储问题,分表解决单表数据量问题
- 实际应用中常常结合使用:先垂直分库(按业务),再水平分表(按数据量)
- 分库分表会引入新的复杂性:分布式事务、跨库查询、全局ID生成等问题需要配套解决方案