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. 自检

  1. profile 里 query_type 与 time_in_nanos 各说明什么?
  2. took 远大于子阶段耗时说明什么?
  3. 五个优化手段按收益排序?
  4. 慢查询阈值怎么配?
  5. 规模化后的三个瓶颈?

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/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。