← 返回首页

生产用户数据超过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 缓存完全够用。分表是"最后的手段"而非"第一步"——过早分表带来的复杂度远大于收益。真正的架构原则是:能不分就不分,能缓存就缓存,能读写分离就读写分离,实在扛不住了再考虑分库分表。