Elasticsearch亿级索引下search_after比from&size查询慢的原因是什么
Elasticsearch search_after 性能劣化问题分析与解答
性能差异根因
从你提供的profile结果可以直接定位问题:next_doc_count 达4.1亿次,查询阶段耗时45秒、收集器阶段耗时30秒,核心原因是ES为了找到search_after对应的位置,遍历了4亿多条符合过滤条件的文档,才拿到后续的10条结果,所以整体耗时达到20秒。
具体触发逻辑如下:
- 你的查询时间范围覆盖1324958207到1724958207接近13年的跨度,search_after传入的时间值1630594662000处在范围的中间偏后位置,加上排序规则是
__time__倒序,ES默认需要从最新的文档(时间最接近1724958207)开始逐一遍历,跳过所有时间大于1630594662000的4亿条文档,才能找到你要的起始位置。 - 你使用from&size时查询的是前几页(from值通常小于1000),此时ES仅需要取前
from+size条TopN结果,不需要遍历大量文档,所以仅需数毫秒即可返回。
两种分页方式的核心区别
- 实现逻辑不同:
from+size是基于偏移量分页,ES会查询出前from+size条符合条件的文档,排序后截断前from条,返回剩余的size条。search_after是基于游标分页,通过上一页最后一条文档的排序字段值作为标记,定位到下一页的起始位置后返回size条结果。 - 适用场景不同:
from+size仅适合浅分页场景,ES默认限制from+size不能超过10000,超过之后性能会急剧下降,且会占用大量内存做排序。search_after天生为深度分页设计,理论上可以无限分页,但是性能高度依赖排序字段的存储结构。 - 数据一致性不同:
from+size分页过程中如果有数据新增、删除,会导致分页偏移错位,出现数据重复或者漏查的问题。search_after基于固定的排序值定位,不受索引数据变更影响,分页一致性更高。 - 性能表现不同:
from+size在from值极小的时候性能极高,随着from值增大性能线性下降。search_after如果可以利用索引排序或者范围过滤快速定位游标位置,分页性能稳定在毫秒级,否则会出现遍历全量文档的性能劣化问题。
优化方案
- 临时优化:调整查询的
__time__范围,把lte设置为search_after传入的时间值1630594662000,直接过滤掉所有时间大于该值的4亿条文档,不需要遍历即可直接定位到目标范围,查询耗时会直接降到毫秒级。 - 永久优化:修改索引配置,设置索引排序和查询排序规则一致,配置参考如下:
{ "index": { "sort.field": ["__time__", "__key__"], "sort.order": ["desc", "desc"] } }
索引按该规则排序后,ES底层存储的文档顺序和查询排序顺序完全一致,search_after可以直接通过索引跳转到游标对应的位置,不需要遍历前置文档,任意深度分页性能都能保持稳定。
内容的提问来源于stack exchange,提问作者MarvinLiu
相关产品推荐
相关产品推荐

