常见的优化查询速度"的方法,主要分成 数据库层、SQL 层、缓存层、接口层、前端层 几类。
查询速度优化的核心是:少查数据、查对索引、减少重复查、把常用结果缓存起来,把复杂统计提前算好。
推荐优化顺序
实际项目里,建议按这个顺序排查:
1. 先定位慢在哪里:数据库慢、接口慢、网络慢、前端渲染慢
2. 找慢 SQL:慢 SQL 日志 / 接口日志
3. 用 EXPLAIN 看有没有走索引
4. 优化索引和 SQL
5. 优化分页和返回字段
6. 高频数据加缓存
7. 统计类数据做预计算
8. 历史大表做归档
1. 加索引:最常见、最有效
如果查询经常按某个字段筛选,就可以给这个字段加索引。
比如经常这样查:
sql
SELECT * FROM user WHERE phone = '138xxx';
那就可以给 phone 加索引:
sql
CREATE INDEX idx_user_phone ON user(phone);
常见适合加索引的字段:
| 场景 | 适合加索引 |
|---|---|
| 经常作为查询条件 | WHERE user_id = ? |
| 经常排序 | ORDER BY create_time DESC |
| 经常分组 | GROUP BY type |
| 经常关联表 | JOIN ... ON order.user_id = user.id |
| 经常唯一查询 | 手机号、邮箱、编码、订单号 |
但不要所有字段都加索引。索引会提升查询速度,但会降低新增、修改、删除速度,也会占空间。
2. 优化 SQL:避免写出慢查询
尽量不要 SELECT *
只查需要的字段:
sql
SELECT id, username, phone FROM user WHERE id = 1;
比这个更好:
sql
SELECT * FROM user WHERE id = 1;
尤其是表里有大字段,比如 content、description、json、text,SELECT * 会拖慢查询。
避免索引失效
比如字段 phone 有索引,但这样写可能用不上索引:
sql
SELECT * FROM user WHERE LEFT(phone, 3) = '138';
因为你对字段做了函数处理。
更推荐:
sql
SELECT * FROM user WHERE phone LIKE '138%';
还有这种也容易导致索引失效:
sql
WHERE DATE(create_time) = '2026-05-28'
建议改成范围查询:
sql
WHERE create_time >= '2026-05-28 00:00:00'
AND create_time < '2026-05-29 00:00:00'
3. 分页优化:避免深分页太慢
普通分页:
sql
SELECT * FROM article ORDER BY id DESC LIMIT 100000, 10;
当偏移量很大时会很慢,因为数据库要先跳过前面 100000 条。
可以改成基于游标的分页:
sql
SELECT * FROM article
WHERE id < 100000
ORDER BY id DESC
LIMIT 10;
通俗理解:
不要告诉数据库"跳过前 10 万条"
而是告诉数据库"从某个 id 往后继续查 10 条"
适合列表、时间线、消息流、日志流。
4. 使用缓存
对于不经常变化、但经常被查询的数据,可以放缓存。
常见缓存对象:
| 数据 | 适合缓存吗 |
|---|---|
| 首页统计数据 | 适合 |
| 字典配置 | 适合 |
| 用户权限菜单 | 适合 |
| 热门文章列表 | 适合 |
| 商品分类 | 适合 |
| 实时余额 | 要谨慎 |
| 库存数量 | 要谨慎 |
常见缓存工具:
| 缓存 | 说明 |
|---|---|
| 本地缓存 Caffeine | 速度快,适合单体服务或局部热点数据 |
| Redis | 适合多服务共享缓存 |
| 浏览器缓存 | 适合静态资源 |
| CDN 缓存 | 适合图片、JS、CSS、公开资源 |
缓存优化的关键不是"加上缓存就完了",而是要设计好:
缓存 key 怎么设计
缓存多久过期
数据更新后怎么删除缓存
是否允许短时间旧数据
缓存击穿、穿透、雪崩怎么处理
5. 减少联表查询
有些慢查询是因为联表太多:
sql
SELECT ...
FROM order o
LEFT JOIN user u ON o.user_id = u.id
LEFT JOIN product p ON o.product_id = p.id
LEFT JOIN shop s ON p.shop_id = s.id;
优化方式:
| 方法 | 说明 |
|---|---|
| 给关联字段加索引 | 例如 order.user_id、product.id |
| 拆成多次查询 | 先查主表,再批量查关联数据 |
| 冗余常用字段 | 例如订单表保存用户昵称、商品名称 |
| 建汇总表 | 把复杂统计提前算好 |
| 建视图或物化表 | 根据业务情况使用 |
对于后台管理系统,很多列表页可以先查主表,再按 id 批量查询其他信息,不一定所有字段都要一次大 JOIN 查出来。
6. 做数据预计算
有些统计类查询每次实时计算会很慢,比如:
sql
SELECT COUNT(*), SUM(amount)
FROM order
WHERE create_time BETWEEN ...;
如果数据量很大,可以定时把结果算好,存到统计表。
比如:
订单明细表 → 每天凌晨统计 → 日统计表
查询时直接查统计表:
sql
SELECT total_amount, order_count
FROM order_day_stat
WHERE stat_date = '2026-05-28';
适合:
场景
首页仪表盘
报表统计
趋势图
大屏数据
月度汇总
排行榜
7. 控制返回数据量
接口慢不一定是数据库慢,也可能是返回数据太多。
优化方式:
| 方法 | 说明 |
|---|---|
| 分页查询 | 不要一次查几千几万条 |
| 字段裁剪 | 只返回页面需要的字段 |
| 大字段懒加载 | 详情页再查正文、备注、附件 |
| 列表页不返回完整内容 | 只返回摘要 |
| 限制导出数量 | 大数据导出异步处理 |
比如闪念列表页只需要:
id、标题、摘要、类型、状态、创建时间
不一定要把完整正文、事件流、附件信息全部查出来。
8. 异步处理慢任务
有些操作不应该卡在查询接口里实时做。
比如:
生成报表
导出 Excel
统计大量数据
调用第三方接口
AI 总结内容
批量处理文件
可以改成:
用户发起任务 → 后台异步处理 → 前端轮询/通知 → 下载结果
这样不是让查询本身变快,而是让用户不用一直等待。
9. 用 EXPLAIN 分析慢 SQL
MySQL 可以用:
sql
EXPLAIN SELECT * FROM user WHERE phone = '138xxx';
主要看几个字段:
| 字段 | 关注点 |
|---|---|
type |
查询类型,最好不是 ALL |
key |
实际用到的索引 |
rows |
预计扫描多少行 |
Extra |
是否出现 Using filesort、Using temporary |
如果 type = ALL,通常表示全表扫描,需要重点优化。
10. 开启慢 SQL 日志
可以让数据库记录执行时间超过某个阈值的 SQL。
比如超过 1 秒的 SQL 记录下来,然后针对性优化。
常见流程:
开启慢 SQL 日志
→ 收集慢查询
→ 用 EXPLAIN 分析
→ 加索引 / 改 SQL / 改分页 / 加缓存
→ 再压测验证
这比凭感觉优化更靠谱。
11. 数据归档或冷热分离
如果表里历史数据很多,但平时只查最近数据,可以做归档。
比如:
order 表:保留最近 6 个月数据
order_history 表:保存历史订单
平时查询只查主表,历史查询再查归档表。
适合:
场景
日志表
操作记录表
订单流水
访问记录
告警记录
审批记录
12. 减少 N+1 查询
这是后端很常见的问题。
错误示例:
先查 100 条订单
然后循环 100 次,每次查一次用户信息
这样会变成:
1 次订单查询 + 100 次用户查询
优化成:
先查 100 条订单
拿到 user_id 列表
一次性批量查询用户信息
在内存中组装
也就是:
1 次订单查询 + 1 次用户批量查询
速度会明显提升。