针对每天新增100万订单的场景,结合查询需求,以下是高性能、高扩展性的分库分表设计方案:
一、分库分表策略
1. 分片维度选择
用户ID分片(核心维度)
sql-- 分片键: user_id -- 分片算法: user_id % 1024 (生成1024个分片) -- 优势:同一用户的订单天然落在同一分片,避免跨库查询
订单ID全局唯一设计
java// 订单ID生成规则(Snowflake变种) // 格式:时间戳(41bit) + 分片ID(10bit) + 自增序列(12bit) // 示例:20231109151600123_1023_4095 → 全局唯一且携带分片信息
2. 分片数量计算
- 数据规模预估markdown
- 日增量:100万 - 年增量:3.65亿 - 分片数量 = 总数据量 / 单表建议最大行数(建议单表≤2000万) - 分片数 = 3.65亿 / 2000万 ≈ 18 → 选择1024分片(预留100倍扩展空间)
3. 分片路由表(可选)
sql
CREATE TABLE shard_route (
user_id BIGINT PRIMARY KEY,
shard_id INT NOT NULL COMMENT '分片编号'
) ENGINE=InnoDB;
二、表结构设计(核心表)
1. 主订单表(按user_id分片)
sql
CREATE TABLE orders (
order_id VARCHAR(32) PRIMARY KEY COMMENT '含分片信息的订单ID',
user_id BIGINT NOT NULL COMMENT '分片键',
amount DECIMAL(12,2) NOT NULL,
status TINYINT NOT NULL COMMENT '0-未支付 1-已支付...',
create_time DATETIME(6) NOT NULL COMMENT '精确到微秒',
update_time DATETIME(6) NOT NULL,
INDEX idx_user_ctime(user_id, create_time) COMMENT '用户订单列表查询',
INDEX idx_ctime_status(create_time, status) COMMENT '运营统计'
) ENGINE=InnoDB
PARTITION BY HASH(user_id) PARTITIONS 1024;
2. 订单扩展表(垂直拆分)
sql
CREATE TABLE order_extension (
order_id VARCHAR(32) PRIMARY KEY,
product_info JSON NOT NULL COMMENT '商品快照',
delivery_info JSON COMMENT '物流信息',
payment_info JSON COMMENT '支付凭证',
FOREIGN KEY (order_id) REFERENCES orders(order_id)
) ENGINE=InnoDB;
三、查询优化方案
1. 用户订单列表查询(条件1)
sql
-- 用户最近3个月订单(分页优化)
SELECT * FROM orders
WHERE user_id = 123456
AND create_time >= '2023-08-01'
ORDER BY create_time DESC
LIMIT 20 OFFSET 0;
-- 索引命中:idx_user_ctime
-- 性能保障:同一分片内查询,无需跨节点
2. 订单详情查询(条件2)
sql
-- 根据order_id直接路由到对应分片
SELECT * FROM orders o
JOIN order_extension oe ON o.order_id = oe.order_id
WHERE o.order_id = '20231109151600123_1023_4095';
-- 性能保障:通过order_id解析分片位置,点查效率O(1)
四、数据生命周期管理
1. 热数据与冷数据分离
sql
-- 自动归档方案
CREATE TABLE orders_archive LIKE orders;
ALTER TABLE orders
PARTITION BY RANGE COLUMNS(create_time) (
PARTITION p202311 VALUES LESS THAN ('2023-12-01'),
PARTITION p202312 VALUES LESS THAN ('2024-01-01'),
PARTITION p_archive VALUES LESS THAN MAXVALUE
);
-- 定期将3个月前数据迁移到归档库
2. 数据清理策略
sql
-- 异步删除已取消订单(避免锁表)
pt-archiver --source h=127.0.0.1,D=test,t=orders \
--where "status=5 AND create_time < NOW() - INTERVAL 30 DAY" \
--dest h=127.0.0.1,D=test,t=orders_deleted \
--no-delete --limit 1000 --commit-each
五、配套架构设计
1. 读写分离
yaml
# ShardingSphere配置示例
spring:
shardingsphere:
datasource:
names: master,slave1,slave2
masterslave:
load-balance-algorithm-type: round_robin
rules:
readwrite-splitting:
data-sources:
pr_ds:
write-data-source-name: master
read-data-source-names: slave1,slave2
2. 缓存加速
java
// 订单详情缓存策略(Redis)
public Order getOrder(String orderId) {
String key = "order:" + orderId;
Order order = redisTemplate.opsForValue().get(key);
if (order == null) {
order = orderDao.selectById(orderId); // 自动路由到正确分片
redisTemplate.opsForValue().set(key, order, 30, TimeUnit.MINUTES);
}
return order;
}
六、性能测试指标
场景 | 预期指标 |
---|---|
订单写入TPS | ≥5000(SSD磁盘) |
用户订单列表查询P99 | ≤50ms(带分页) |
订单详情查询P99 | ≤10ms(缓存命中率90%+) |
分片扩容时间 | <30分钟(在线不停机) |
总结:通过用户ID哈希分片+订单ID嵌入式路由的设计,配合垂直分表、读写分离和缓存策略,可在保证每秒1.1万+订单写入(100万/86400≈11.57/s)的同时,实现用户维度和订单维度的毫秒级查询。建议配合ShardingSphere中间件实施,并通过定期数据归档维持长期性能。