大家好呀,我是小米,一个31岁还保持好奇心、天天折腾新技术的程序员。
上周去帮一个朋友做面试辅导,结果第一道题就把他卡住了。
面试官问:"我们系统有一张大表,字段特别多,性能慢,你会怎么优化?"
朋友理直气壮地说:"我会建索引!"
面试官笑了笑又追问:"那如果字段太多,索引也没法解决呢?"
他愣住了。
于是我在旁边小声提醒他一句: "垂直分区啊,哥!"
他回去查了一天,才发现这个词在不同文章里讲法千奇百怪,什么 "纵向切表""按模块拆库""字段分表" ......越看越乱。
今天,小米就带你一口气讲清楚:
垂直分区到底是啥?它和水平分表有什么区别?在MySQL8.x里又该怎么做?
故事开始:那张让人窒息的"用户表"
先来看看这张表,你是不是也见过这样的:
| id | username | password | email | phone | avatar | bio | last_login | login_ip | create_time | update_time | role | status | address | hobby | login_count | last_device | ... |
没错,这就是那种 "全能用户表" ,把所有字段都往里面塞。
一查一堆字段,几十个列,有的存字符串,有的存 JSON,部分字段甚至几乎不用。
结果呢?
- 查询慢:SELECT * 拉太多无用字段;
- 索引失效:字段太多,覆盖索引成本高;
- I/O 飙升:每次都要扫描大块数据;
- 内存 Cache 命中率下降。
这时候,就轮到我们的主角登场了------垂直分区。
什么是垂直分区?
一句话解释:
垂直分区,就是把一张字段很多的大表,按字段维度拆成多张"小表"。
比如,我们把刚才那张"全能用户表"拆开:
- user_base:存放基础信息(id, username, password, email, phone)
- user_profile:存放扩展信息(avatar, bio, hobby, address)
- user_login:存放登录行为(last_login, login_ip, last_device, login_count)
它像是把一个超级胖子切成三块肌肉匀称的运动员。这样做的好处很多:
- 减少I/O开销:查询时只扫描需要的字段。
- 提升缓存命中率:更小的数据页,更高效的内存利用。
- 安全与权限隔离:敏感数据(密码)单独存储、权限控制。
- 维护更方便:表结构清晰,字段职责单一。
垂直分区 vs 水平分表
经常有同学搞混:分区、分表、分库到底是啥?
来,小米给你一个最通俗的比喻:
一句话总结:
垂直分区解决"列太多"的问题,水平分表解决"行太多"的问题。
那垂直分区该怎么做?
1. 分析字段使用频率
看看哪些字段经常查、哪些很少查。
比如登录时只查用户名和密码,那扩展信息完全没必要在同一张表。
2. 按功能拆表
通常我们会这样拆:
- 基础表(Core Table) :最核心、最常访问的数据
- 扩展表(Extension Table) :低频字段或不定期更新的数据
- 日志表(Behavior Table) :行为类或统计类数据
3. 用主键关联
一般都会用同一个主键,比如用户id。
当然,频繁 join 的话也要注意性能,可以通过缓存或视图优化。
4. 保证事务一致性
垂直分区后,多表更新可能带来事务问题。解决方案:
- 使用同一个数据库事务;
- 或者用消息队列异步同步非核心表。
MySQL8.x 有什么新变化?
MySQL8 对存储引擎、优化器、JSON字段都做了大升级,这对垂直分区来说是大利好。
1. JSON字段更灵活
如果只是部分可选字段,可以考虑存储 JSON,而不是立即分表。MySQL8 的 ->> 操作符、索引支持已经非常完善。
2. 表分区(Partitioning)更智能
虽然垂直分区是逻辑层面的拆分,但 MySQL8 的原生分区功能也能配合使用,比如按用户ID做 range 或 hash 分区,查询效率更高。
3. CTE + 窗口函数辅助查询
在多表 join 后,使用窗口函数做排序、聚合比以前方便太多,性能也更好。
实践案例:我们怎么救活一张"胖表"
还记得开头那张"全能用户表"吗?
我们团队曾经有一张类似的"产品表",字段多达 80 个,查询慢得离谱。
我们做了两步:
1、拆表:
- product_core:核心字段(id, name, price, stock)
- product_detail:扩展字段(description, spec, image_url)
- product_stat:统计字段(view_count, sale_count)
2、引入缓存:
- 核心字段放 Redis(快速响应)
- 扩展字段懒加载
3、最终结果:
- 查询性能提升 3 倍
- CPU 使用率下降 40%
- 页面加载速度从 800ms 降到 200ms
更关键的是,业务逻辑更清晰了。新同事上手时不再被那堆字段吓到。
面试官喜欢追问的 3 个细节
面试中,答完"垂直分区"后,面试官可能会追问:
1、分区后会不会增加 JOIN?性能会不会更差?
回答:短期内 JOIN 会增加,但长期来看查询集中、缓存命中率提升,整体性能更好。
2、垂直分区和微服务有什么关系?
回答:垂直分区是数据库层面的拆分,微服务是应用层面的拆分。两者理念相通,但作用层次不同。
3、什么时候不该垂直分区?
回答:如果字段少、访问场景简单,就不要拆。过度设计会适得其反。
总结
今天,小米和你聊了一个看似简单但常被误解的概念------垂直分区。
它不是"玄学调优",而是一种结构化思维:
把一个复杂臃肿的表,拆成多个专注的表,让查询更快、逻辑更清晰。
记住这句话:
垂直分区让数据库更"轻",也让开发更"爽"。
END
最后,留一个小问题给你:
如果有一张订单表,既要频繁查订单状态,又要保存历史操作日志,你会怎么分区?
欢迎留言区一起交流,小米每天都会亲自回复~
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号"软件求生",获取更多技术干货!