什么是分库?分表?分库分表?

#中间件#面试八股

什么是分库?分表?分库分表?

结论:分表把一张大表按规则拆成多张物理小表,解决单表数据量与索引深度问题;分库把数据拆到多个数据库实例,解决单机 CPU、IO、连接数上限。两者叠加就是「分库分表(Sharding)」。垂直拆分按业务或字段切,水平拆分按行切;先定位瓶颈再拆,能靠索引、归档、读写分离解决的,不要上分片。

一、四种拆分方式

方式拆分依据典型动作解决的问题主要代价
垂直分库业务域订单库、用户库、商品库独立部署单库资源争抢、故障隔离跨库事务、跨库 JOIN
垂直分表字段冷热订单主表 + 订单详情表(大字段)单行过大、IO 放大多一次关联查询
水平分表行t_order 拆成 t_order_0..15单表行数、B+ 树层高路由、分页、聚合
水平分库行同规则落到 ds0..ds3单实例写入、连接数瓶颈分布式事务、扩容迁移
                  垂直:按业务/字段切                 水平:按行切
   ┌──────────────┐        ┌──────────┐       ┌────────────────────────┐
   │   单体库      │        │  订单库   │       │  t_order(1 亿行)      │
   │ 用户/订单/商品 │  ───►  │  用户库   │       │   ├─ t_order_0  625 万  │
   └──────────────┘        │  商品库   │       │   ├─ t_order_1  625 万  │
                           └──────────┘       │   └─ ...                │
                                              └────────────────────────┘

垂直拆分的产物是「不同库、不同表结构」;水平拆分的产物是「同结构的多张表」,因此只有水平拆分才需要分片键(Sharding Key)与路由算法。

二、什么时候才该拆

行业里常引用的经验阈值:单表行数超过 500 万行,或单表容量超过 2 GB,就应考虑分表。这是经验值而非硬指标——行宽 200 字节和 2 KB 的表,同样 500 万行完全是两个量级。

判定顺序建议:

  1. 先看慢查询:索引缺失、回表、深分页往往能解释大部分性能问题。
  2. 再看容量:单表超过阈值且无法归档,才进入分表候选。
  3. 最后看写入:单库写入 QPS 打满、连接数耗尽时,才需要分库。

三、配置样例

ShardingSphere 5.x 的逻辑表配置,把 t_order 映射到两个库各两张表:

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://10.0.0.11:3306/order_db
        username: app
        password: ${ORDER_DB_PWD}
      ds1:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://10.0.0.12:3306/order_db
        username: app
        password: ${ORDER_DB_PWD}
    rules:
      sharding:
        tables:
          t_order:
            actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: db_mod
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: tbl_mod
        sharding-algorithms:
          db_mod:
            type: MOD
            props:
              sharding-count: 2
          tbl_mod:
            type: MOD
            props:
              sharding-count: 2

SQL 侧看起来没有变化:SELECT * FROM t_order WHERE user_id = 42 由中间件改写成对 ds0.t_order_x 的单表查询。

四、常见追问

Q1:分库分表与读写分离、分区有什么区别? 读写分离只分担读流量,写与容量瓶颈照旧;分区(Partition)由数据库自己拆文件,仍在同一实例,突破不了单机上限;分库分表在应用层或中间件层完成,能真正横向扩展。

Q2:拆完一定要引入中间件吗? 不一定。表数量少、路由简单时,在 DAO 层用 user_id % 4 拼表名即可;需要跨库事务、归并分页、在线扩容时,ShardingSphere、Vitess 这类中间件更省心。

Q3:拆得越细越好吗? 不是。每多一个库就多一份连接池、备份、监控和 DDL 成本;上千张表的路由与运维复杂度远超收益。常见做法是「逻辑分片数一次定够,物理节点按需扩」。

小结

  • 垂直拆分按业务或字段,水平拆分按行;只有水平拆分才需要分片键与路由算法。
  • 分表治容量,分库治并发与连接数,两者可独立也可叠加。
  • 上分片前先排除索引、SQL、归档能解决的问题;拆得越细,运维成本越高。
笔记加载中…