做语义搜索或者推荐系统的同学,大概率都会碰到一个问题:向量检索到底放在哪里做?是直接在数据库里做,把向量存进PostgreSQL,用pgvector扩展建一个HNSW索引,一份数据一套系统搞定;还是单独跑一个HNSWlib进程,追求极限的查询吞吐?这两个方案背后其实都是HNSW这一经典的图索引算法,但工程形态完全不同,性能表现、运维成本和适用场景也差异巨大。本文就从多个维度把这两者掰开揉碎对比一下。

一、两者的底层原理与工程形态差异
HNSW(Hierarchical Navigable Small World)是一种分层可导航小世界图算法。它把向量组织成多层图结构,上层稀疏、下层稠密,查询时从最高层的入口点贪心搜索,逐层下降,最终在底层完成精细的近邻查找。这种结构让查询复杂度接近对数级别,在高维向量空间中仍然能保持不错的召回率和延迟表现。
HNSWlib是这个算法作者本人的C++参考实现,它是一个纯库,没有存储引擎、没有查询语言、没有事务系统,只提供建索引、插入向量、搜索近邻这几个核心接口。你需要在应用层自己管理向量数据与业务数据的关联,自己处理持久化和故障恢复。它的优势是零负担:没有数据库的开销,插入和查询都直接操作内存中的图结构,速度极快。
而PostgreSQL这边,pgvector扩展从0.5版本开始引入了HNSW索引支持,底层实现同样借鉴了hnswlib的思路。但区别在于,PostgreSQL把图索引嵌入到了自己的存储体系里。索引页通过PostgreSQL的缓冲区管理器读写,向量可以和普通业务表放在同一张表中,用SQL直接join、过滤、聚合。这是一种完全不同的工程取舍:牺牲一部分性能,换取生态完整性。
二、性能与资源占用对比
单看纯检索吞吐,HNSWlib几乎是天花板级别的。因为它所有数据都在内存里,查询路径上没有磁盘IO、没有锁竞争、没有SQL解析开销。在百万级向量的场景下,HNSWlib单线程QPS轻松达到数千,配合多线程可以线性扩展。而PostgreSQL的HNSW索引要经过SQL解析、执行计划、缓冲区访问、进程间锁等一系列环节,同样的硬件条件下QPS通常是HNSWlib的几分之一。
内存占用方面两者也有明显差别。HNSWlib的索引完全驻留内存,100万条768维float向量,光向量数据就要约3GB,加上图结构的邻接表,总内存占用会更高。PostgreSQL的HNSW索引则依赖共享缓冲区(shared_buffers),热门数据页会被缓存,冷数据可能落盘,这意味着在内存不足时PostgreSQL能靠磁盘扛住,而HNSWlib直接就建不了索引或者频繁swap。
pgvector建索引的典型写法如下,通过m和ef_construction参数控制图的连接数和建图质量:
-- 创建向量列,768维
CREATE TABLE docs (
id bigserial PRIMARY KEY,
content text,
embedding vector(768)
);
-- 建HNSW索引,使用余弦距离
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
-- 查询时通过ef_search调节召回率与速度
SET hnsw.ef_search = 100;
SELECT id, content
FROM docs
ORDER BY embedding <-> '[0.1, 0.2, ...]'
LIMIT 10;
可以看到,PostgreSQL方案的最大亮点是向量过滤可以和其他条件组合。比如在推荐场景里,经常要限定类目、地域、时间窗之后再做向量检索,这种混合查询在pgvector里就是一条SQL的事,而用HNSWlib你就得先自己过滤候选集,或者在应用层做复杂的预筛选逻辑,召回率还容易受影响。
三、数据管理能力与运维成本
数据管理是PostgreSQL的绝对主场。向量数据和业务数据放在同一数据库里,天然享受ACID事务保障:插入向量和更新业务状态可以在同一个事务中提交或回滚,数据一致性不需要应用层操心。备份恢复直接用pg_dump或者物理备份工具,主从复制、时间点恢复都是现成能力。
HNSWlib本身不提供任何持久化机制,进程重启索引就没了,需要自己从原始向量重建,或者用它的save_index、load_index接口做快照。如果业务要求向量实时更新,就得自己设计增量策略,处理重建索引期间的可用性问题,这套工程量并不小。
pgvector的HNSW索引还有一个特性值得注意:它是基于MVCC的,删除向量并不立即清理图节点,而是留下死元组,需要靠VACUUM机制回收。在写入频繁的场景下,索引膨胀会拖慢查询,需要合理设置autovacuum参数,这一点和PostgreSQL普通B-tree索引的运维经验是相通的。
四、选型建议:什么场景该用哪个
综合来看,两者的选择标准可以归纳为以下几点:
- 数据规模中小、业务数据强关联:向量量级在千万以内,且检索需要和结构化条件深度组合,优先选PostgreSQL加pgvector,一套系统解决所有问题,运维成本最低。
- 纯检索、超高吞吐:如果业务就是单纯的近邻查询,没有复杂过滤,QPS要求极高,比如在线广告的召回层,HNSWlib或基于它的专用向量库更合适。
- 内存预算有限:数据量大到内存放不下全量索引时,PostgreSQL的缓冲区机制能优雅降级,HNSWlib则会面临硬件成本压力。
- 向量频繁更新:pgvector的事务和MVCC机制处理增量更新更从容,HNSWlib的增量插入在大量删除场景下容易产生图质量退化。
还有一点提醒:如果选了专用方案又舍不得PostgreSQL的事务能力,可以考虑混合架构——业务主数据留在PostgreSQL,向量检索交给独立的向量数据库(很多底层就是HNSWlib及其变体),两边通过ID关联。这样各取所长,代价是引入了双写一致性问题,需要根据业务容忍度来权衡。
总的来说,没有绝对的最优解。PostgreSQL的HNSW索引胜在生态整合和数据治理,HNSWlib胜在极致性能和轻量灵活。理解自己的业务形态——查询模式、数据规模、更新频率、团队技术栈——比记住任何基准测试数字都重要。建议在真实数据上做一轮召回率和延迟的压测,用数据说话再做决定。
PostgreSQLHNSWlib向量检索修改时间:2026-09-04 19:58:38