DEBUG.WIKI
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

Polars 明明先 sort,when 结果却按旧顺序返回

Polars 的顺序观察优化可能漏算 when 条件列,在两个分支都是常量时移除排序。检查排序后的行对应关系,局部关闭相关优化,不用更换执行引擎掩盖问题。

LazyFrame 已经按 x 排序,最后只选出 when(x > 1).then(1).otherwise(0),结果仍像按原始行顺序计算。把 x 也选出来,结果又正常。遇到这种差异,应检查优化器是否错误认为结果不观察行顺序。

这项问题在 Polars 2.0 的 streaming 查询中出现,更简单的排序表达式也能触发;并不只影响 streaming。条件分支依赖列,两个返回分支却都是常量时,顺序依赖分析可能忽略条件这一侧,删去仍有意义的排序。不能把所有未指定顺序的 group-by 结果也归到本题。

用明确的小输入检查排序是否被丢掉

下面的例子按 x 升序后,输出应依次对应 1、2、3,即 0、1、1:

import polars as pl

query = (
    pl.LazyFrame({"x": [3, 1, 2]})
    .sort("x")
    .select(pl.when(pl.col("x") > 1).then(1).otherwise(0).alias("flag"))
)
result = query.collect(
    optimizations=pl.QueryOptFlags(check_order_observe=False)
)

关闭这一项是局部规避和对照方式,保留其他优化的默认设置。2.1.0 正式接口中有 check_order_observe,但 QueryOptFlags 被标为不稳定接口;固定依赖版本,并在升级时检查参数是否仍存在,不能把它当作永久不变的业务 API。

真实查询中保留原排序键、窗口分组、null 位置与输出列,只对受影响执行入口设置该项。若业务依靠同值行的稳定次序,还需要原来约定的额外排序键;关闭优化不会凭空给相同键补出确定顺序。

加一列不是充分验收

同时选择排序键有时会让优化器保留顺序,可用于定位依赖分析。它也可能改变查询计划,因此“调试时加列就正确”不能证明只输出 flag 的正式查询也正确。

不要只把引擎从 streaming 换成 in-memory 后就关闭问题:同一排序场景在两种引擎中都可能触发。只比较 flag 的计数也不够,乱序不会改变 0 和 1 的总数;应将输出与稳定行身份或预期排序位置对齐。

对于没有排序契约的查询,先明确下游是否本来就不应依赖行顺序。不能为了复现这个问题给所有结果追加任意排序,改变原来的窗口或采样含义。

更换 Polars 版本后,用相同查询计划检查常量分支、列分支、上游排序和窗口条件。恢复默认优化后仍能保持正确的行对应关系,才移除临时选项。