【向量检索引擎】pgvector 内核对照:同进程 SQL 扩展与专用引擎差在哪一层

💡 原文中文,约10100字,阅读约需24分钟。
📝

内容提要

pgvector v0.8.0将HNSW索引作为PostgreSQL索引访问方法实现,向量以varlena存储于8KB页中,与业务表共享WAL、缓冲区和VACUUM。相比Milvus,它支持同进程事务和SQL,但受限于页装箱、默认后过滤和资源争用。选型应基于隔离需求与生命周期管理,而非单纯比较ANN算法性能。

🔎

延伸解读

页装箱:8KB 页的几何约束

pgvector 将 HNSW 图节点直接存储在 PostgreSQL 的 8KB 索引页中,每个节点包含向量副本和邻居指针。以 768 维 float32 向量为例,每页仅能容纳约 2 个节点,这导致随机遍历时对缓冲区命中率敏感。这种装箱限制源于页大小与向量大小的比例,而非 HNSW 算法本身。相比之下,Milvus 的 Sealed 段使用文件映射布局,不受此约束。理解这一差异有助于解释为何在相同数据集上,pgvector 的索引可能占用更多 I/O。

过滤机制:默认后过滤与 iterative scan

pgvector 的 HNSW 索引默认采用后过滤,即先执行 ANN 搜索,再应用过滤条件,这可能导致召回率下降。v0.8.0 引入的 iterative scan 通过扩展扫描范围来缓解,但仍是事后过滤,并非图内过滤。文章建议结合 B-Tree 索引、部分索引或分区来优化过滤。相比之下,专用引擎如 Milvus 通常将过滤条件编码为 bitset 并在图搜索前应用,从而减少无效计算。

同进程架构的权衡

pgvector 作为 PostgreSQL 扩展,与业务表共享 WAL、缓冲区和 VACUUM,支持同进程事务和 SQL,简化了数据一致性管理。然而,这也意味着 ANN 查询与 OLTP 负载争用同一实例的 CPU 和内存资源,且索引构建和删除受制于 PostgreSQL 的生命周期。Milvus 则通过存算分离,将索引构建和查询分流到独立节点,提供更好的隔离性。选型时应根据资源隔离需求和运维复杂度权衡,而非单纯比较算法性能。

Q&A

pgvector 和 Milvus 在架构上的核心区别是什么?

pgvector 作为 PostgreSQL 的扩展,将 HNSW 索引实现为索引访问方法,向量以 varlena 存储在 8KB 页中,与业务表共享 WAL、缓冲区和 VACUUM,支持同进程事务和 SQL。而 Milvus 采用存算分离架构,向量数据存储在段文件中,由独立的 Data Node 构建索引,支持独立的资源池和生命周期管理。

pgvector 的 HNSW 索引在 8KB 页上如何存储?

pgvector 的 HNSW 索引页也是 8KB,block 0 为元页,其后为图页。图页中存储 HnswElementTupleData(包含向量数据和最多 10 个堆 TID)和 HnswNeighborTupleData(邻居列表)。构建时尽量将 element 和 neighbor 放在同一页以减少随机读。

pgvector 的过滤机制是怎样的?

pgvector 默认采用 post-filter,即先进行 ANN 索引扫描,再应用过滤条件。这可能导致过滤后结果不足。从 0.8.0 起支持 iterative scan,可以扩大扫描范围直到满足结果数量或达到限制,但仍是事后过滤,不是图内过滤。

pgvector 与 Milvus 在事务支持上有何不同?

pgvector 支持与业务表同事务,插入后在同一事务内即可查询,遵循 MVCC。Milvus 通常跨系统,事务一致性由业务主键对齐,可见性由一致性级别控制。

pgvector 的 HNSW 索引与 Milvus 的 Knowhere 在算法上有何关系?

两者算法同源,都基于 HNSW 算法(Malkov & Yashunin, 2020)。区别在于工程实现:pgvector 将图嵌入 PostgreSQL 的 8KB 页和 MVCC 中,而 Milvus 将图挂在段文件上,由 Knowhere 引擎管理。

pgvector 在资源争用方面有哪些特点?

pgvector 与 OLTP 查询共享同一实例的 CPU、shared_buffers、WAL 和 autovacuum,因此建索引、ANN 查询和业务查询会争抢资源。Milvus 的 Data Node 可以独立池化,减少对在线查询的影响。

pgvector 的向量存储格式是怎样的?

向量以 varlena 类型存储,结构包含长度、维度、未使用字段和 float 数组。768 维向量约 3080 字节,通常可放入单页,更高维可能触发 TOAST。

pgvector 的 iterative scan 与图内过滤有何区别?

iterative scan 是扩大扫描范围的事后过滤,不是图内过滤。它通过从 discarded 堆恢复候选或继续扫描来增加结果,但可能增加延迟和锁持有时间。

🏷️

标签

➡️

继续阅读