數據庫如何實現垂直拆分,原理是啥?
當數據庫數據量大到影響性能時,“水平切分” 和 “垂直拆分” 都是降低數據規模、提升性能的手段,但兩者思路截然不同,我們可以用更通俗的方式拆解清楚:
一、水平切分:“按用戶分組” 式拆分
可以理解為 “把同一類數據按規則分散到多個庫 / 表”。比如以用戶 ID(uid)為依據,用 “取?!?的規則(如uid % 4),把原本一個庫(或表)的所有數據,拆到 4 個庫(或表)里。
它的特點很明確:
- 每個拆分后的庫 / 表結構完全一樣(就像每個小組的 “容器” 長得一樣);
- 每個庫 / 表數據完全不重復(每個小組只存自己的用戶,沒有交集);
- 所有庫 / 表的數據合起來,就是完整的全量數據(所有小組加起來是全部用戶)。
類比一下:把所有用戶按 ID 分成 4 個組,每個組一個數據庫,每個庫只存自己組的用戶數據,結構都一樣 —— 這樣單個庫的數據量就小了,查詢和寫入的壓力也分散了。
二、垂直拆分:“按屬性分類” 式拆分
可以理解為 “把一個表的不同屬性拆到多個表”。如果一個表字段太多、單行數據太大(比如用戶表既有基本信息,又有簽名、長簡介這些冷門字段),就把不同類型的屬性拆到不同表。
它的特點是:
- 每個拆分后的表結構完全不同(因為存的屬性類型不一樣);
- 表之間通過主鍵(如 uid)關聯(就像用 “身份證號” 把不同表的信息綁在一起);
- 所有表的數據合起來,才是完整的業務數據(比如用戶的基本信息 + 簽名簡介,合起來才是完整用戶)。
舉個實際例子,原本的user表有很多字段:
user(
uid bigint, -- 用戶ID
name varchar(16), -- 姓名
pass varchar(16), -- 密碼
age int, -- 年齡
sex tinyint, -- 性別
flag tinyint, -- 狀態標識
sign varchar(64), -- 個性簽名(長文本)
intro varchar(256)-- 個人簡介(超長文本)
...
);垂直拆分后,會拆成兩個表:
user_base(存高頻訪問的短字段):
user_base(
uid bigint,
name varchar(16),
pass varchar(16),
age int,
sex tinyint,
flag tinyint,
...
);user_ext(存低頻訪問的長字段):
user_ext(
uid bigint,
sign varchar(64),
intro varchar(256),
...
);三、垂直拆分的 “底層邏輯”:為什么這么拆能提升性能?
這得從數據庫的 “緩沖池(buffer_pool)” 說起 —— 數據庫會把磁盤里的數據加載到內存緩沖池里,以此減少磁盤 IO,提升速度。但內存是有限的,緩沖池的 “緩存效率” 就成了關鍵:
- 緩沖池以 “頁” 為單位存儲數據,邏輯上按 “行” 緩存。如果一行數據很短,緩沖池能存的行數就多;如果一行很長,能存的行數就少。
- 把高頻訪問、字段短的屬性(如姓名、年齡)聚在一個表,能讓緩沖池緩存更多行數據;把低頻訪問、字段長的屬性(如簽名、簡介)拆出去,能減少緩沖池的無效占用。
舉個直觀例子:
- 假設緩沖池內存是 1G,未拆分的user表一行數據 1k,最多能緩存100 萬行;
- 垂直拆分成user_base(一行 0.1k)和user_ext后,user_base能緩存1000 萬行。
這樣一來,大部分高頻訪問都能命中緩沖池(不用讀磁盤),數據庫的響應延遲會大幅降低,吞吐量也會顯著提升。
總結:兩者的核心區別與適用場景
維度 | 水平切分 | 垂直拆分 |
拆分依據 | 按 “數據行” 的維度(如用戶 ID) | 按 “字段屬性” 的維度(如字段長度、訪問頻率) |
結構特點 | 拆分后庫 / 表結構完全相同 | 拆分后表結構完全不同 |
核心價值 | 分散數據量,解決 “數據太多” | 優化緩存效率,解決 “訪問太慢” |
典型場景 | 用戶量極大的業務(如社交、電商) | 字段多且冷熱不均的業務(如用戶表、訂單表) |
簡單來說,水平切分是 “把用戶分組存”,解決數據量過載;垂直拆分是 “把字段分類存”,解決訪問性能瓶頸 —— 兩者結合,能讓海量數據的數據庫跑得又快又穩。

























