Skip to content

针对每天新增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中间件实施,并通过定期数据归档维持长期性能。

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我