823 字
约 2 分钟
8
S13-J03 · 检索性能优化:从定位到规模化
适用读者:查询变慢但不知道慢在哪的人。
前置:S13-J02。
实测环境:ES 8.15.3(2026-11-05)。
覆盖旧文:638(213) = 213 点。
覆盖扩展:E-S13-009(profile 与慢日志)。
上一篇:S13-J02 · 集群、分片、副本与脑裂
下一篇:S13-A01 · MySQL → ES 同步。
1. 一句话结论
ES 的查询慢只有三个来源:扫太多文档(filter 没生效)、打太多分(用 match 干了 term 的活)、取太多字段(_source 太大)。profile API 能把这三点量化。
2. 实测:profile 输出结构
{"profile": true, "query": {"match": {"title": "tutorial"}}, "size": 1}
实测:
query_type = TermQuery
time_in_nanos = 15400268 (约 15.4 ms)
took = 74 ms (整个请求)
| 字段 | 含义 |
|---|---|
query_type |
查询被改写成什么(match → TermQuery) |
time_in_nanos |
该查询子阶段的耗时 |
took |
服务端总耗时(不含网络) |
读法:took 远大于 time_in_nanos → 时间花在别处(fetch 阶段、聚合、排序)。
3. 五个优化手段(按收益排序)
| # | 手段 | 说明 |
|---|---|---|
| 1 | filter 替代 must |
不打分、可缓存 |
| 2 | term 替代 match(keyword 字段) |
省分析开销 |
| 3 | _source 过滤 |
"_source": ["title"] 减少传输 |
| 4 | 分页用 search_after |
避免深翻(B03 的上限) |
| 5 | 只读索引 _forcemerge |
减少段数(J01) |
"为什么 filter 更快":不打分 + 结果可缓存——同样的过滤条件第二次几乎零成本。
4. 慢查询的定位路径
① 看 took(服务端耗时)
② profile=true → 找耗时最大的 query 子句
③ 看 fetch 耗时(_source 大?字段多?)
④ 看分片数(扫描的分片越多越慢)
⑤ 慢日志:index.search.slowlog.threshold.query.warn
| 阈值配置 | 建议 |
|---|---|
query.warn |
1s |
query.info |
500ms |
fetch.warn |
1s |
5. 规模化后的三个瓶颈
| 瓶颈 | 表现 | 方案 |
|---|---|---|
| 分片过多 | 查询要协调 N 个分片 | 减少分片 / ILM 滚动 |
| 深翻 | 超过 max_result_window |
search_after |
| 大聚合 | 内存/CPU 打满 | 预聚合 / 独立 OLAP |
6. 五个误区
| 误区 | 真相 |
|---|---|
"took 就是查询耗时" |
含 fetch/聚合等全部服务端时间 |
"must 和 filter 差不多" |
打分有成本、不可缓存 |
"match 总比 term 好" |
keyword 字段上 term 更快 |
| "深翻只是慢" | ES 有硬上限 |
| "加节点能解决慢查询" | 分片/查询写法问题加机器无效 |
7. 自检
- profile 里
query_type与time_in_nanos各说明什么? took远大于子阶段耗时说明什么?- 五个优化手段按收益排序?
- 慢查询阈值怎么配?
- 规模化后的三个瓶颈?
8. 下一篇
S13-A01 · MySQL → ES 同步:全量、增量与一致性
优化讲完,进架构师层:数据怎么从数据库进 ES,怎么保证不丢不重。
本篇属于系列《S13 · 搜索与文档存储》。旧文来源:A-638;扩展点 E-S13-009。profile 输出为 ES 8.15.3 实测。
S13-J03 · 检索性能优化:从定位到规模化
https://www.clxhxhhr.top/posts/5365/ 评论
0 条
还没有评论,先写一条吧。