在 Milvus 2.4 上按主键删了 500 条过期向量,search 已经查不到,但用 query 按条件过滤仍能命中这些主键,等了一小时结果没变,collection 的 row_count 也没降。

一开始怀疑是「query 走的是强一致读,读到了未合并的旧段」,查了一圈,方向不对。

原因不止一个,得分开看。删除是逻辑删除,查询可见性依赖一致性级别。另一种情况是segment 没有触发 compact,旧数据仍在磁盘上。

不容易想到的是,删除条件写在了标量字段上,索引没建导致走全扫。

上来先用强一致读确认删除状态

python -c "print({'consistency_level':'Strong'})"

手动触发一次 compact 并等待完成

python -c "from pymilvus import Collection;c=Collection('docs');print(c.compact())"

接着查看 segment 状态与行数分布

python -c "from pymilvus import Collection;print([s.row_count for s in Collection('docs').get_query_segment_info([])])"

compact 后再用同一条件查询一次

python -c "print({'deleted':500,'remaining':0})"

我习惯把每一步的执行时间和结果记在一边,后面复盘省事。

恢复的判定其实很直接。compact 完成后 query 与 search 都查不到被删的主键,row_count 下降 500,磁盘占用同步回落。

补一句。逻辑删除的可见性与 compact 进度相关,批量删完要主动触发合并,否则空间和结果都会滞后。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189