ES|QL|节点级 TopN 之后做延迟物化,排序查询少搬很多数据

简介: 9.3 给 ES|QL 加了节点级延迟物化。

9.3 给 ES|QL 加了节点级延迟物化。这条改动不影响查询结果,只影响查询怎么执行——所以你看不到任何变化,但某些排序查询会明显变快。

说明

来源和边界先交代:本文的依据出自 v9.4.2 标签下的官方文件(9.3.0.yml、EsqlCapabilities.java、ComputeService.java),文中引用的原文均来自这些文件。我没有启动集群、也没有跑测试,示例取自官方示例;哪些是文档写明、哪些是我的推断,正文里逐处标注。

01-9.3.0

图 1:官方文件 9.3.0.yml(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 9.3.0.yml

官方条目

9.3 的 changelog 标为 feature(9.3.0.yml 第 39–42 行 @ v9.4.2),area: ES|QL,PR 132962。

只有一行 summary。实质内容来自源码。

02-EsqlCapabilities

图 2:官方文件 EsqlCapabilities.java(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 EsqlCapabilities.java

先说物化是什么

ES|QL 查询里有两类数据:

  • 排序键:SORT 用的字段;
  • 其余列:最终结果要返回的其他字段。

物化(materialization)指的是:把一行需要的字段值真正取出来。

朴素做法是先把所有列都取出来,再排序。问题在于:如果最终只要 Top 10,你却先把 100 万行的所有列都取出来了——其中 99.99% 的工作是白做的。

延迟物化就是把顺序反过来:

  1. 先只取排序键;
  2. 排序、截断,只留下 Top N;
  3. 这时候才去取这 N 行的其余列。

省掉的是步骤 1 里那些"取了又扔掉"的列。

03-ComputeService

图 3:官方文件 ComputeService.java(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 ComputeService.java

为什么省得下来

关键在于取列是有成本的。

ES 里数据按列存(doc values),"取某一列的值"意味着读磁盘、解压、反序列化。一行有 20 个字段,取全部 20 列和只取 1 个排序列,成本差可能是一个数量级。

所以延迟物化的收益取决于一个比例:

[
\frac{\text{最终返回的行数}}{\text{参与排序的行数}}
]

这个比例越小,省得越多。 SORT ... | LIMIT 10 扫了 100 万行、只要 10 行,收益最大;如果 LIMIT 很接近总数,就没什么可省的了。

(说明:这个公式是对机制的理解,官方没给过性能数据,也未实测。)

"节点级"是什么意思

标题里有个限定词值得说清楚:Node level。

ES|QL 是分布式执行的,大致分两层:

  • 数据节点:各自扫描本地分片,做本地计算,把结果发给协调节点;
  • 协调节点:汇总各数据节点的结果,做最终归并。

"节点级延迟物化"发生在数据节点这一侧:每个数据节点自己做 TopN 时,就用延迟物化的方式——先只取排序键,本地排完取 Top N,再补齐这 N 行的其他列,然后才发给协调节点。

这一步优化的是节点间传输的数据量,不只是本地计算量。少取的列既不用读,也不用往网络上发。

它和数据库的"回表"是同一件事

延迟物化不是新做法,数据库领域用了很久。提这个是因为——理解它是个通用思路,比记住 ES|QL 的某个开关更有用。

最直观的对照是数据库的"回表"。二级索引里只有索引列和主键,先用索引找到符合条件的行,再拿主键回主键索引取完整行。先定位、后取数,跟这里是一样的。

再近一点的例子:分页查询的优化。不要用 OFFSET 10000 让数据库算出前 10000 行再扔掉——那和"先把所有列取出来再排序"是同一类浪费。

所以看到"延迟物化"这个词,可以立刻反应过来:它的对立面是"提前把数据备齐"。而后者在什么情况下浪费,是可以靠常识判断的——取了又没用上的,就是浪费。

源码里是怎么标的

ES|QL 有一套 capability(能力开关)机制,用于控制新特性。这条改动对应的是 EsqlCapabilities.java 第 2114–2116 行(源码 @ v9.4.2):

 * Enables late materialization on node reduce. See also QueryPragmas.NODE_LEVEL_REDUCTION
ENABLE_REDUCE_NODE_LATE_MATERIALIZATION,

注释里给了两个信息:

  • 它作用于 node reduce 阶段(就是前面说的数据节点归并);
  • 它和 NODE_LEVEL_REDUCTION 有关联——后者是另一个开关。

所以准确的说法是:这条改动让 node reduce 这一步支持延迟物化。

执行路径上的分支

ComputeService.java 里能看到它怎么参与决策(第 1228–1238 行,源码 @ v9.4.2):

boolean runNodeLevelReduction,
boolean reduceNodeLateMaterialization,
...
if (reduceNodeLateMaterialization == false && runNodeLevelReduction == false) {
   
    return passThroughReduction;
}

这段代码的意思是:两个开关都关着的时候,走一条直通路径——不做任何归约优化,直接把数据往上游传。

只要有一个开着,才进入后面的归约计划构建。

提这段代码是说明一件事:它是执行计划里的一个分支,不是一个全局开关。开关状态参与的是"用哪个执行计划"的决策,而不是"要不要排序"这种语义层面的事。

这也印证了开头那句——它不改变结果,只改变怎么算。

什么时候能吃到这个优化

按理解,要满足几个条件:

  • 有排序(SORT)——没有 TopN 就谈不上"TopN 之后";
  • 排序之后有截断(LIMIT)——不截断的话全都要返回,省不了;
  • 返回的列不只是排序列——如果只 select 排序列,本来就不用取别的。

典型受益场景:宽表上做 SORT ... | LIMIT n,且最终返回的字段比较多。

反过来说,下面这些场景收益很小:

  • 只返回排序列;
  • LIMIT 很大,接近命中总数;
  • 数据量本来就小。

(这一段是根据机制推断的,官方没有给出具体的适用条件清单,不保证完整。)

对前面几条 ES|QL 优化做个归位

9.x 在 ES|QL 上做了不少执行层优化,前面写过几篇。放一起看能更清楚各自的定位:

篇 优化 作用阶段
FORK 与 INLINE STATS FORK / INLINE STATS 查询语法层
节点级 TopN 后的延迟物化(本篇) 节点级延迟物化 执行计划:数据节点归约
doc_values skippers doc values skippers 存储层:过滤加速
HNSW 早停默认开启 HNSW 早停 向量检索层

层次各不相同。延迟物化属于"执行计划"这一层——它不动语法、不动存储,只改变计算步骤的顺序。

这类优化的特点是用户完全无感。你不需要改查询、不需要改 mapping、不需要配任何东西,升级之后某些查询就变快了。

无感是好事也是麻烦:好事是不用迁移;麻烦是你没法主动确认它生效了。想知道只能靠 PROFILE 看执行计划,或者对比升级前后的延迟。

这类"用户无感"的改动该怎么对待

9.x 的改动按"用户能否感知"可以分成两类,对待方式完全不同:

类型 例子 该怎么对待
改行为的 _source mode 设置迁移 _source.mode 搬家、discovery-ec2 换 SDK v2 ec2 配置失效 要在升级前排查,因为它们会静默不生效
只改性能的 本篇、doc_values skippers skippers 升级后观察即可,不用提前准备

判断标准很简单:这条改动会不会让"你以为的"和"实际发生的"不一致?

  • 会 → 属于第一类,要在升级前动手;
  • 不会,只是快慢变化 → 属于第二类,升级后看指标。

反复强调这个区分,是因为两类混在一起处理会两头不讨好:把性能优化项当 breaking 去排查,浪费时间;把静默失效项当性能优化放过去,迟早踩坑。

还有一点:第二类的风险不在"它有问题",而在你把性能变化归因错了。升级后延迟变好或变差,原因可能有很多条改动叠加——升级前后各留一次基线,比事后猜原因有用。

要不要主动验证

判断是多数团队不需要专门验证。

理由:这条改动不改变结果,只可能变快,不存在"升级后出问题"的风险。你要担心的是那些会改变行为的 breaking,不是它。

值得验证的情况只有一种:你在做性能敏感的容量规划。比如某条查询的延迟已经卡在 SLA 边缘,那就值得升级前后各测一次,看看有没有改善。

验证办法就是用 PROFILE 看执行计划里有没有对应的算子。但说实话,看延迟变化比看执行计划更直接——你关心的是快没快,不是用了哪种算法。

别为了吃优化而改查询

最后说一个看法。

知道"延迟物化对 SORT | LIMIT 有效"之后,一个自然的念头是:把查询都写成这个形式?

不建议。 理由:

  • 查询应该表达你要什么,不是"怎么写更快"。执行计划优化是 ES 的事,不该由使用者操心;
  • 今天有效的写法,明天可能就无效了——优化器会变,但你的查询语义不该跟着变;
  • 为性能扭曲查询,会让后来读代码的人困惑。

正确的顺序是:先写对的查询,性能不够再优化。而优化的手段应该是改索引、改数据模型、或者升级版本,不是改查询的形状去迎合当前优化器的实现细节。

那什么情况下值得改查询

上面说"别为优化改查询",但不是绝对的。把边界说清楚,免得变成一句无用的口号。

值得改的情况:查询本身有语义层面的浪费。比如:

  • SELECT * 但只用其中三列——这是真的多取了,改掉是修正而不是迎合优化器;
  • 先 SORT 再在应用层截断——应该把 LIMIT 写进查询,让截断发生在服务端;
  • 排序键用了高基数的长字符串,而业务上按时间排序也满足需求——这是换了需求,不是换了写法。

这几种改动的共同点是:改完之后查询表达的还是同一件事,只是不再浪费。

不值得改的情况:查询已经准确表达了意图,只是为了"可能更快"去调整写法顺序、拆分或合并子句。这类改动看不到收益,还增加理解成本。

判断依据就一条:改完以后,这个查询是更好懂了,还是更难懂了? 更好懂 → 值得;更难懂 → 除非有实测收益,否则不值得。

写在最后

这条改动很小,也很典型:一个执行计划层面的优化,用户无感,只影响性能。

一,延迟物化 = 先排后取。 只用排序键排序,截断到 Top N,然后才取这 N 行的其余列。

二,收益取决于"返回行数 / 参与排序行数"。 这个比例越小省得越多。宽表 + 小 LIMIT 受益最大。

三,它在数据节点归约阶段生效,同时省下本地读取和节点间传输。

我的判断是:要不要为它调整查询写法,先看两条——表够不够宽、LIMIT 够不够小。两条都不满足时,省下的那点读取大概率看不出来。

另外诚实标注了三处未核实的:性能收益幅度(官方无数据、未实测);具体的适用条件(按机制推断,官方没给清单);这个 capability 的默认开启状态(看到有这个 capability,但未逐个确认它在 9.3 里默认是开还是关——要确认则查 EsqlCapabilities 里该枚举的 isEnabled() 实现)。

参考

本文对照 Elasticsearch v9.4.2 标签的 changelog 与源码核对,引文与代码逐字取自原文。性能收益幅度官方未提供数据、未实测;适用条件依据机制推断,官方未给清单;该 capability 的默认开启状态未逐个确认,已在正文标注。撰写时未启动集群、未运行测试。

目录
相关文章
|
云安全 安全 网络安全
|
2天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
|
16天前
|
JSON 程序员 数据格式
最新版Notepad++下载、安装、配置保姆级教程(附官网安装包)
Notepad++ 是一款免费开源、轻量快速的 Windows 文本编辑器,支持多标签、语法高亮、代码折叠与宏录制,体积小、启动快、资源占用低,兼容 x64/x32/ARM 架构,是程序员和文字工作者的高效利器。
3960 1
|
9天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
2058 2
|
15天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
2608 46
|
3天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
520 1
|
12天前
|
Web App开发 人工智能 前端开发
2026 年 AI 浏览器怎么选?Ego Lite、Tabbit、Chrome DevTools MCP 深度对比,开发者到底该用哪个?
2026年AI浏览器选型指南:Ego Lite专注多Agent协同(Mac优先),Tabbit国产首选,原生支持Windows与Codex控制;Chrome DevTools MCP非浏览器而是开发者利器,深度集成Console/Network/Performance调试能力,让AI真正“看懂并验证”前端代码。
1509 3
|
10天前
|
开发者 索引
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
Open Plugin Market 是一个开放插件索引平台,收录800+优质DSH插件,支持分类浏览、智能推荐与随机发现。无需安装市场,粘贴索引地址即可一键接入,网页版直访 dshopen.org,助力小开发者被看见。(239字)
2077 1
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
|
8天前
|
人工智能 Linux API
Magpie, 轻量本地AI网关!免费Token用不完!
Magpie 是开源AI编程模型调度网关,上线一月获1.8万Star。它通过本地高性能网关统一托管多平台API密钥、账号与免费额度,实现跨Agent的模型秒级切换、静默额度轮换与资源复用,显著降低碎片化管理成本。(239字)
Magpie, 轻量本地AI网关!免费Token用不完!

热门文章

最新文章