海量数据处理
「数据量大的时候怎么处理?」——回答框架:先定位瓶颈在哪(存储层?查询层?写入层?),再按成本从低到高逐层演进。不要一上来就分库分表。
查询侧优化(成本最低,先做)
- 索引优化:联合索引遵循最左前缀;等值列在前、范围列在后;用覆盖索引避免回表。
- 只查需要的列:避免
SELECT *,减少网络与内存开销,才有机会覆盖索引。
深分页优化
LIMIT 1000000, 10 会扫描并丢弃前 100 万行。两种方案:
-- 方案 A:游标 / 滚动分页(记录上一页最大 id),恒定代价
SELECT * FROM user_visit_log
WHERE user_id = 1001 AND id < #{lastId}
ORDER BY id DESC LIMIT 10;
-- 方案 B:延迟关联(必须跳页时),先在索引上定位主键再回表
SELECT t.* FROM user_visit_log t
JOIN (SELECT id FROM user_visit_log
WHERE visit_time >= '2026-10-27'
ORDER BY id LIMIT 1000000, 10) x ON t.id = x.id;
预聚合
明细数据只用于审计,统计一律走汇总表(定时任务 / 增量聚合)。这是「访问次数」这类场景的标准答案,详见《访问统计表设计》。
写入侧优化(高吞吐写入)
- 异步化:请求线程只写 MQ(或内存队列),消费者批量落库(攒 500 条或每秒一批插入),DB 压力降一个数量级。
- 批量插入:
INSERT ... VALUES (...), (...)批量写,比循环单条插入快 10 倍以上。 - 缓冲合并:实时计数先走 Redis
INCR,定时任务把 Redis 的值刷进汇总表。
架构侧演进(数据量持续增长)
| 手段 | 适用场景 | 要点 |
|---|---|---|
| 读写分离 | 读多写少 | 主库写、从库读;注意主从延迟(写后立即读要走主库) |
| 冷热分离 / 归档 | 历史数据占比高 | 近 3 个月热数据在线,更早的归档到历史表 / 低成本存储 |
| 分库分表 | 单表持续超千万且索引、归档仍撑不住 | 垂直拆(按业务)、水平拆(按 user_id 哈希或按时间);引入 ShardingSphere;提前想好跨片查询与分布式 ID |
| 换 OLAP 存储 | 复杂统计分析 | 明细导入 ClickHouse / Doris,统计分析类查询天然快几十倍 |
:::warning 分库分表是最后手段 单表千万级不是必然要拆——索引合理 + 预聚合 + 归档后,单表几千万也常常够用。分库分表引入即接受复杂度:跨片 join、分布式事务、扩容迁移。面试时先讲「我会先排除索引和统计方式的问题,再谈拆分」。 :::