MySQL的垂直分表(Vertical Sharding/Table Splitting)是一种数据库优化技术,通过将一张表中不同字段拆分到多张表中,以解决单表数据量大、访问性能下降的问题。
一、什么是垂直分表?
想象一张user
表,包含id
(用户ID)、username
(用户名)、password
(密码)、avatar
(头像URL)、bio
(个人简介)、address
(地址)、contact
(联系方式)等20个字段。
其中,id
、username
、password
是高频访问字段(如登录时每次都需查询),而avatar
、bio
等是低频访问字段(仅个人主页展示时才用)。
垂直分表就是将这张表按「访问频率」或「字段关联性」拆分为:
user_core
(核心表):存放id
、username
、password
等高频字段;user_profile
(资料表):存放avatar
、bio
、address
等低频字段。
两表通过id
关联,需要完整信息时通过JOIN
查询,日常高频操作仅访问user_core
。
二、理论依据:数据库访问的「局部性原理」
垂直分表的核心依据是计算机科学中的局部性原理:
- 时间局部性:最近访问过的数据,短期内可能再次被访问(如用户登录时反复查询账号密码);
- 空间局部性:访问一个数据时,其相邻数据(同表其他字段)可能被一同加载(数据库按「数据页」读取,单表字段越多,每页存储的行数越少)。
当表字段过多时:
- 单条记录占用空间大,相同存储容量下能缓存的记录数减少,磁盘IO次数增加;
- 高频操作被迫加载大量无关的低频字段,浪费内存和带宽;
- 表结构复杂,维护成本高(如新增字段可能影响索引效率)。
垂直分表通过拆分字段,让高频操作仅涉及「小而精」的表,提升缓存利用率和查询效率。
三、如何使用垂直分表?
1. 拆分原则
- 按访问频率拆分:高频字段(如订单表的
order_id
、status
)和低频字段(如remark
、log
)分开; - 按字段大小拆分:大字段(如
text
类型的文章内容、blob
类型的图片)单独拆到一张表,避免拖累小字段查询; - 按业务关联性拆分:将属于不同业务模块的字段拆分(如用户表中,登录相关字段和社交相关字段拆分)。
2. 实操步骤(以user
表为例)
(1)创建拆分后的表
-- 核心表(高频访问)
CREATE TABLE user_core (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL, -- 加密存储
create_time DATETIME NOT NULL,
INDEX idx_username (username)
);
-- 资料表(低频访问)
CREATE TABLE user_profile (
user_id INT PRIMARY KEY, -- 与user_core.id关联
avatar VARCHAR(255),
bio TEXT,
address VARCHAR(255),
contact VARCHAR(50),
FOREIGN KEY (user_id) REFERENCES user_core(id) ON DELETE CASCADE
);
(2)数据迁移
-- 从原表迁移数据到核心表
INSERT INTO user_core (id, username, password, create_time)
SELECT id, username, password, create_time FROM old_user;
-- 迁移到资料表
INSERT INTO user_profile (user_id, avatar, bio, address, contact)
SELECT id, avatar, bio, address, contact FROM old_user;
(3)查询方式
- 仅需核心信息时(如登录验证):
SELECT id, username FROM user_core WHERE username = 'test';
- 需要完整信息时(如个人主页):
SELECT c.*, p.avatar, p.bio FROM user_core c LEFT JOIN user_profile p ON c.id = p.user_id WHERE c.id = 1;
3. 适用场景
- 表中存在大量低频访问的大字段(如
text
、blob
); - 高频查询仅用到表中少数字段(如90%的查询只涉及30%的字段);
- 单表字段过多(超过20个),导致DDL(新增/修改字段)操作缓慢。
四、注意事项
- 避免过度拆分:拆分后JOIN操作会增加复杂度,需在「拆分粒度」和「查询效率」间平衡;
- 事务一致性:跨表更新时需用事务保证数据一致(如同时修改
user_core
和user_profile
); - 索引优化:拆分后需重新设计索引(核心表优先优化高频查询的索引)。
垂直分表本质是「空间换时间」,通过合理拆分字段,让数据库资源(内存、IO)更集中于高频操作,从而提升整体性能。