垂直分库和水平分表是应对单库单表性能瓶颈的延后策略,非初期必需;垂直分库按业务域拆分数据库实现职责分离,牺牲跨库join与强一致性;水平分表按分片键分散数据以缓解单表压力,需规避非分片键查询与全局id问题。

垂直分库和水平分表不是“必须一开始就做”的事情,而是当单库单表真正扛不住写入压力或查询延迟时才考虑的拆分策略;盲目提前分库分表反而会让事务、关联查询、运维成本陡增。
垂直分库:按业务域切分 database,不是按表名随便分
垂直分库本质是把一个大库按业务边界(比如用户、订单、商品)拆成多个独立数据库,每个库有自己完整的表结构和数据。关键不在于“表多”,而在于“职责分离”。
-
user_db只存user、address、auth_token等强用户域表,不放order - 跨库关联(如查用户+最新订单)无法用
JOIN,得靠应用层两次查询 + 内存拼接,或走异步冗余字段(如订单表里冗余user_nickname) - 事务天然被打破:
下单涉及user_db扣余额 +order_db写订单 → 必须用最终一致性方案(如本地消息表 + 补偿任务) - MySQL 主从复制仍可各自配置,但跨库 DDL(如加字段)要人工对齐,容易漏
水平分表:同一张表数据按规则分散到多个 table,核心是路由逻辑
水平分表解决的是单表数据量过大(比如 order 表超 5000 万行)导致的慢查询、DDL 锁表时间长问题。它不改变表结构,只拆数据。
- 常用分片键(shard key):用
user_id(查用户订单快)、order_no(防热点,但查询难定位)或created_at(适合冷热分离,但范围查询友好,等值查询差) - 分片算法别硬编码:用取模(
user_id % 4)简单但扩容麻烦;推荐一致性哈希或虚拟槽位(如sharding-jdbc的StandardShardingAlgorithm) -
SELECT * FROM order WHERE order_no = 'xxx'能精准路由到一张子表;但SELECT * FROM order WHERE status = 'paid'会广播到所有子表,性能反降 - 唯一 ID 不能依赖
AUTO_INCREMENT:得用雪花算法(Snowflake)、UUID 或号段模式(leaf-segment)生成全局唯一键
中间件选型不是看功能多,而是看它是否掩盖了你本该面对的问题
ShardingSphere-JDBC、MyCat、Vitess 这些中间件能帮你自动路由 SQL、合并结果,但它们不会替你处理分布式事务、跨节点排序分页、或者索引失效这类底层问题。
-
ShardingSphere-JDBC是 JDBC 层代理,无额外服务节点,适合 Java 应用;但它会让ORDER BY ... LIMIT在分页时先拉全量再内存排序,大数据量下 OOM 风险高 -
MyCat是代理层,支持SELECT跨库JOIN,但实际执行是各库查出结果再合并,遇到GROUP BY或复杂子查询容易不准 - 所有中间件都绕不开「非分片键查询」:如果业务大量需要按
phone查用户,而分片键是user_id,那就得建单独的phone → user_id映射表,或用 Elasticsearch 同步补充 - 监控必须跟上:
sharding-sphere-proxy的sql.show开关不能长期开着,否则日志爆炸;建议用metrics暴露分片命中率、慢 SQL 分布
真正难的不是怎么配中间件或写分片规则,而是判断哪张表该分、什么时候开始分、以及接受“有些查询就是不能再用原来的方式写了”。分库分表之后,EXPLAIN 看不到真实执行计划,SHOW PROCESSLIST 查不到跨节点会话,连备份都要逐个库做——这些细节比语法本身更消耗工程判断力。










