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 == 0
  • user_1:user_id % 4 == 1
  • user_2:user_id % 4 == 2
  • user_3:user_id % 4 == 3

每张表只有 2500 万行,查询快多了。

核心思想:数据量太大,单表装不下,就水平切分。每张表结构一样,数据不一样。

避坑指南:我曾经犯过一个错——用时间字段做分表键。比如按月分表,结果热门月份的数据量暴增,冷门月份几乎没数据。分表不均匀,热点问题没解决。后来我改用 user_id 哈希,才真正均匀了。

水平分库:按库拆

水平分库,和水平分表思路一样,但拆的是库。

比如用户表有 1 亿行,单库连接数撑不住了。那就拆成 4 个库:

  • db_user_0:user_id % 4 == 0
  • db_user_1:user_id % 4 == 1
  • db_user_2:user_id % 4 == 2
  • db_user_3:user_id % 4 == 3

每个库独立部署,连接数、CPU、内存都分散了。

水平分库和水平分表经常一起用,叫「分库分表」。比如先分 4 个库,每个库再分 4 张表,总共 16 张表。

注意:水平分库后,跨库查询、聚合、排序都变得复杂。比如你要查全服等级前 100 的玩家,得从 4 个库分别查,再在内存里合并排序。所以,能不分库就不分库,分表能解决就别动库。

四个概念,一张表总结

概念 拆什么 怎么拆 解决什么问题
垂直分库 按业务模块 连接数、CPU 瓶颈
垂直分表 按字段访问频率 IO、内存浪费
水平分表 按行取模/范围 单表数据量过大
水平分库 按行取模/范围 单库连接数、IO 瓶颈

我的建议

别一上来就想着分库分表。先做垂直分库,再考虑垂直分表。如果数据量还是大,再水平分表。最后才考虑水平分库。

为什么?因为分库的代价最大。跨库事务、分布式查询、数据迁移,每一样都够你喝一壶的。

我记得有个项目,一开始就搞了 16 个库 64 张表,结果业务还没跑起来,运维先崩溃了。后来我帮他们回退到 4 个库 16 张表,性能完全够用。

所以,分库分表是手段,不是目的。够用就好,别过度设计。

一句话记住:垂直分库按业务,垂直分表按字段,水平分表按行,水平分库按库。先垂直后水平,先分表后分库。