P17 查询 200 条数据耗时 200ms,怎么在 500ms 内查询 1000 条数据
面试题:现在查 200 条数据要 200ms,怎么优化到 500ms 内查出 1000 条(性能提升 4 倍)?
先定位瓶颈
"200 条 200ms"本身就不快,说明瓶颈大概率不在数据量,而在:
- N+1 查询:循环里逐条查库/调接口;
- 网络开销:客户端与 DB 多次往返(RTT);
- 未走索引 / 回表;
- 单条 SQL 里 join 了太多表 / 函数计算;
- 序列化、日志、锁等额外开销。
优化手段
1. 批量查询,消灭 N+1
不要循环 1000 次单查,改用一次批量查询:
sql
SELECT * FROM t WHERE id IN (...1000个id...)或分段 IN(每批 500~1000 个),把 1000 次 RTT 变成 1~2 次。
2. 建好索引 / 覆盖索引
确保查询走索引,需要哪些字段就建覆盖索引,避免回表:
sql
CREATE INDEX idx_user_status ON t(user_id, status, create_time);用 EXPLAIN 看执行计划:type 是否为 ref/range、Extra 是否出现 Using index。
3. 减少返回数据量
- 只 select 需要的字段,不
SELECT *; - 大文本/大对象拆到单独表或走缓存;
- 数据压缩、分页。
4. 加缓存
热点查询结果放 Redis/本地缓存(Caffeine),命中缓存毫秒级返回。
5. 并行化
如果 1000 条数据天然分布在多个分片/多个服务,可以并发查询再合并:
java
// CompletableFuture 并发查多个分片
CompletableFuture.allOf(futures...).join();6. 异步与连接池
- 用连接池避免频繁建连;
- 查询结果异步返回,不阻塞请求线程。
加分点
- 回答要先分析再动手:先 EXPLAIN 看执行计划,再谈优化;
- "1000 条 500ms" = 平均 0.5ms/条,批量 + 索引 + 覆盖索引后完全可行;
- 防止过度设计:数据量小的时候,优化 N+1 和索引往往立竿见影。
一句话总结
先 EXPLAIN 定位瓶颈(大概率是 N+1 或没走索引),再用批量查询 + 覆盖索引 + 减少返回列 + 缓存/并行,把 1000 次查询变成几次高效查询即可满足 500ms 指标。