Polars 读 Delta 表,已删除的行又出现了
Polars 2.1.0 读取带删除向量的 Delta 表时,分区路径编码不一致可能漏用删除掩码。核对相同快照、特殊字符分区与读取器,避免直接扫描 Parquet 绕过事务日志。
同一张 Delta 表在支持删除向量的读取器中只剩两行,Polars 却读出三行,其中一行早已逻辑删除。先确认两边读的是同一个表版本;如果差异集中在分区值含空格、斜杠、百分号或非 ASCII 字符的文件,再检查路径编码与 deletion vector 的匹配。
在 Polars 2.1.0、deltalake 1.6.6 的组合中,触发条件是:分区字符串经 URI 编码保存在文件路径中,删除向量一侧保留编码形式,待扫描文件一侧却是解码后的路径。两者按字符串连接时没有匹配,删除掩码便未用于对应文件。没有特殊字符的分区可以正常,不能只拿它验收整张表。
文件仍在,不代表那一行还属于表
Delta 的逻辑删除可以记录在删除向量里,底层 Parquet 文件未必立即重写。正确读取需要同时考虑事务日志、活动文件、表版本和行级删除掩码。直接 scan_parquet() 读取目录会绕过这些信息,可能连旧文件也一起读入,不是可靠的对照方法。
保留当前表路径、明确的 Delta version、Polars/deltalake 版本和出问题的分区值。在受控环境选取已知主键,比较支持当前表特性的读取器与 Polars 对同一快照的结果;不要让一个读最新快照、另一个读历史快照。对云存储还要核对相同的根目录和访问配置。
观察重点是被删除主键是否仍返回,而不是仅比较总行数。两处差异刚好抵消,也可能让行数看起来相同。包含百分号的值尤其应保留原始路径文本,别在诊断记录中手动替换后再比较。
先确认另一条读取路径的结果
受影响结果若用于账目、同步或下游写入,应先停止把这份结果当作有效快照。可以临时将相同表版本交给已经核对正确、支持该 deletion vector 的读取器,再按原数据契约传递结果;这会改变执行成本和依赖,需要明确容量与快照一致性。
不要用删除 Parquet、清理 _delta_log、执行 VACUUM 或重写所有分区来掩盖读取差异。这些操作会影响表历史与恢复能力,也没有修正客户端的编码匹配。已经从错误结果生成的下游数据,需要按原始快照和主键重新核对,升级库不会自动撤销它们。
也不宜在应用外层对所有路径反复 unquote()。百分号可能本来就是分区值的一部分,多次解码会把不同路径折叠到一起。2.1.0 在这一步仍直接连接两侧路径;局部解码后不再漏掉某个分区,并不能保证其余路径仍匹配正确。
采用后续正式修正时,验收普通分区、空格、/、% 与非 ASCII 分区,以及确实启用和没有启用删除向量的表。确认删除掩码匹配、未删除行保留,且读取的是预期版本。若仍有差异,保留错误结果和原表,避免将未经确认的数据覆盖回来源。


