3、分库分表核心概念:垂直分库、水平分库、垂直分表、水平分表,一张图讲清楚
说实话,很多新手一听到「分库分表」这四个字,脑子里就一团浆糊。
什么垂直水平,什么分库分表,排列组合一下就是四个概念。我当年刚入行时也绕晕过,直到自己动手画了一张图,才真正搞明白。
今天我就用这张图,把四个核心概念给你讲透。
先问一个问题:为什么要分?
说白了,数据库扛不住了。
要么是数据量太大,一张表几千万上亿行,查询慢得像蜗牛。要么是并发太高,一个库的连接数撑爆了。要么是业务太复杂,所有表挤在一个库里,互相干扰。
分库分表,就是把这些压力拆开。怎么拆?两个维度:
- 按「库」拆:解决连接数、IO 瓶颈
- 按「表」拆:解决单表数据量过大
再交叉一下,就有了四种组合。
一张图,四个概念
我习惯用这个矩阵来记:
| 分库 | 分表 | |
|---|---|---|
| 垂直 | 垂直分库 | 垂直分表 |
| 水平 | 水平分库 | 水平分表 |
嗯,就这么简单。但每个概念背后的逻辑,你得吃透。
垂直分库:按业务拆
垂直分库,就是把不同业务模块的表,放到不同的数据库里。
比如一个游戏项目,有用户模块、充值模块、战斗日志模块。以前全塞在 game_db 一个库里。后来发现,充值高峰期,整个库的 CPU 飙到 90%,连带着用户登录都卡了。
怎么办?拆!
user_db:放用户账号、角色信息pay_db:放订单、充值记录log_db:放战斗日志、行为数据
每个库独立部署,互不干扰。这就是垂直分库。
核心思想:按业务领域拆分,每个库只负责一块业务。
我的经验:垂直分库是第一步,也是最容易做的一步。我在项目中遇到过一个坑——拆分后事务不好管了。以前一个库内事务搞定,现在跨库了,得引入分布式事务。所以拆之前,先梳理清楚哪些操作必须在一个事务里。
垂直分表:按字段拆
垂直分表,就是把一张宽表,按字段的访问频率拆成多张窄表。
你想想看,一张游戏角色表,可能有 50 个字段。其中角色名、等级、经验这些字段,每次登录都要查。但装备详情、技能加点这些,只有打开背包或技能面板时才用到。
把高频字段和低频字段拆开:
role_base:role_id, name, level, exp, gold(高频)role_detail:role_id, equipment, skill_tree, achievement(低频)
这样,每次查询只加载需要的字段,IO 和内存都省了。
注意:垂直分表后,两张表通过 role_id 关联。如果业务上经常需要同时查两张表的数据,那就得做 JOIN。JOIN 太多反而影响性能。所以拆之前,先分析业务查询模式。
水平分表:按行拆
水平分表,是把同一张表的数据,按某种规则分散到多张结构相同的表中。
比如用户表 user,有 1 亿行数据。查询 WHERE user_id = 123 时,虽然走索引,但索引树太大,IO 次数多。
按 user_id 取模分表:
user_0:user_id % 4 == 0user_1:user_id % 4 == 1user_2:user_id % 4 == 2user_3:user_id % 4 == 3
每张表只有 2500 万行,查询快多了。
核心思想:数据量太大,单表装不下,就水平切分。每张表结构一样,数据不一样。
避坑指南:我曾经犯过一个错——用时间字段做分表键。比如按月分表,结果热门月份的数据量暴增,冷门月份几乎没数据。分表不均匀,热点问题没解决。后来我改用 user_id 哈希,才真正均匀了。
水平分库:按库拆
水平分库,和水平分表思路一样,但拆的是库。
比如用户表有 1 亿行,单库连接数撑不住了。那就拆成 4 个库:
db_user_0:user_id % 4 == 0db_user_1:user_id % 4 == 1db_user_2:user_id % 4 == 2db_user_3:user_id % 4 == 3
每个库独立部署,连接数、CPU、内存都分散了。
水平分库和水平分表经常一起用,叫「分库分表」。比如先分 4 个库,每个库再分 4 张表,总共 16 张表。
注意:水平分库后,跨库查询、聚合、排序都变得复杂。比如你要查全服等级前 100 的玩家,得从 4 个库分别查,再在内存里合并排序。所以,能不分库就不分库,分表能解决就别动库。
四个概念,一张表总结
| 概念 | 拆什么 | 怎么拆 | 解决什么问题 |
|---|---|---|---|
| 垂直分库 | 库 | 按业务模块 | 连接数、CPU 瓶颈 |
| 垂直分表 | 表 | 按字段访问频率 | IO、内存浪费 |
| 水平分表 | 表 | 按行取模/范围 | 单表数据量过大 |
| 水平分库 | 库 | 按行取模/范围 | 单库连接数、IO 瓶颈 |
我的建议
别一上来就想着分库分表。先做垂直分库,再考虑垂直分表。如果数据量还是大,再水平分表。最后才考虑水平分库。
为什么?因为分库的代价最大。跨库事务、分布式查询、数据迁移,每一样都够你喝一壶的。
我记得有个项目,一开始就搞了 16 个库 64 张表,结果业务还没跑起来,运维先崩溃了。后来我帮他们回退到 4 个库 16 张表,性能完全够用。
所以,分库分表是手段,不是目的。够用就好,别过度设计。
一句话记住:垂直分库按业务,垂直分表按字段,水平分表按行,水平分库按库。先垂直后水平,先分表后分库。