← 返回首页
生产用户数据超过1亿是怎么存储的?为什么不做用户的分表
亿级用户数据的存储方案
1亿用户数据量其实并不算特别大,现代数据库技术完全有能力应对。是否需要分表,取决于具体的业务场景和数据规模。
先算一笔账
假设用户表有以下字段:
| 字段 | 大小 |
|---|---|
| id (BIGINT) | 8 字节 |
| username (VARCHAR 50) | ~50 字节 |
| email (VARCHAR 100) | ~100 字节 |
| phone (VARCHAR 20) | ~20 字节 |
| password_hash | 64 字节 |
| 其他字段(注册时间、状态等) | ~100 字节 |
| 单行总计 | 约 350 字节 |
1亿行数据:1亿 × 350字节 ≈ 35GB
加上索引(通常占数据量的 30%-50%),总存储量大约在 50GB 左右。
这个数据量对于现代数据库来说,单表完全可以承载。MySQL InnoDB 单表支撑数亿数据是常见实践。
为什么很多场景不需要分表
单表性能足够
- MySQL 单表在合理索引下,亿级数据的查询性能依然可以满足大部分业务需求。
- 用户表的核心查询通常是
WHERE id = ?或WHERE phone = ?,走主键/唯一索引,时间复杂度 O(log n),1亿数据只需约 27 次 B+ 树节点查找。
分表带来的复杂度远超收益
分表看似解决了存储问题,但引入了大量新问题:
- 跨表查询困难:分页、排序、聚合操作需要合并多张表的结果。
- 分布式事务:跨表写入需要保证一致性,复杂度急剧上升。
- ID 生成:自增 ID 不再适用,需要引入雪花算法、号段模式等分布式 ID 方案。
- 扩容迁移:数据重新分片时,需要停服或双写迁移,运维成本极高。
- ORM 适配:MyBatis、JPA 等框架对分表的支持有限,需要额外中间件(如 ShardingSphere)。
用户数据的增长速度并没有想象中快
1亿用户可能需要 5-10 年才能积累到,而数据库硬件(SSD、内存)的升级速度远快于数据增长速度。加内存、换 SSD 的成本远低于分表的开发和维护成本。
真正需要的优化手段(替代分表)
索引优化
-- 核心查询走索引,避免全表扫描
CREATE UNIQUE INDEX idx_phone ON users(phone);
CREATE INDEX idx_created_at ON users(created_at);
读写分离
写请求 → 主库(Master)
读请求 → 从库(Slave1, Slave2, ...)
用户表通常是读多写少的场景,读写分离可以大幅提升读性能。
缓存层
请求 → Redis 缓存(热点用户数据) → 缓存未命中 → MySQL
活跃用户的数据缓存在 Redis 中,大部分请求根本不会打到数据库。
冷热数据分离
-- 热数据:最近1年活跃的用户,放在主库
SELECT * FROM users WHERE last_login > DATE_SUB(NOW(), INTERVAL 1 YEAR);
-- 冷数据:长期不活跃的用户,归档到历史表或廉价存储
SELECT * FROM users_history WHERE last_login < DATE_SUB(NOW(), INTERVAL 1 YEAR);
什么时候才真正需要分表
| 条件 | 说明 |
|---|---|
| 单表数据量超过 5-10 亿 | B+ 树层级增加,查询性能开始下降 |
| 单库磁盘超过 2TB | 备份、恢复、迁移变得困难 |
| 写入 QPS 超过单机瓶颈 | 单库写入 TPS 通常在 5000-10000,超过需要分库 |
| 业务明确要求数据隔离 | 如多租户 SaaS 场景 |
如果确实需要分表,怎么做
分片策略
- Hash 分片:
shard = hash(user_id) % N,数据均匀分布,但范围查询困难。 - 范围分片:
id 1-1000万 → 表0,范围查询友好,但容易数据倾斜。 - 一致性哈希:扩容时只需迁移少量数据。
常用中间件
- ShardingSphere(Apache 顶级项目,国内主流)
- MyCat
- Vitess(YouTube 开源,适合超大规模)
总结
1亿用户数据 ≈ 50GB 存储量,单表 + 合理索引 + 读写分离 + Redis 缓存完全够用。分表是"最后的手段"而非"第一步"——过早分表带来的复杂度远大于收益。真正的架构原则是:能不分就不分,能缓存就缓存,能读写分离就读写分离,实在扛不住了再考虑分库分表。