PostgreSQL Rust 向量搜尋 AI pgvector pgvectorscale

pgvector 撐到千萬條向量就開始吃光 RAM:pgvectorscale 用 StreamingDiskANN 把索引搬回硬碟,成本壓到 Pinecone 的四分之一

pgvectorscale 由 Timescale 團隊用 Rust 打造,透過 StreamingDiskANN 索引跟 Statistical Binary Quantization 兩項核心技術,讓 Postgres 的向量搜尋在千萬級規模下反過來壓過 Pinecone。本文拆解它的架構、與 pgvector 的分工,以及在既有專案導入的實務步驟。

pgvector 這兩年幾乎是 Postgres 生態圈導入向量搜尋的預設答案,把 embedding 直接放在關聯式資料旁邊、搭配 SQL filter 一起查是它最大的賣點。但實務上跑到千萬條向量以上,HNSW 索引開始把記憶體吃到見底、查詢延遲拉高到三位數毫秒,維運成本反而追不上 Pinecone、Qdrant 這些專門引擎。pgvectorscale 由 Timescale 團隊用 Rust 打造,透過 StreamingDiskANN 索引跟 Statistical Binary Quantization 兩項核心設計,把 Postgres 在千萬級向量下的效能拉到跟 Pinecone 平手甚至反超,自架成本壓到大約四分之一。

HNSW 撐不住的地方在哪裡

pgvector 的 HNSW 實作本身沒問題,早期論文的水準也還原得夠完整。真正的痛點是它把整個圖結構跟所有向量都塞在記憶體裡:一個 1536 維的 float32 向量佔 6 KB,1000 萬條就是 60 GB 純向量,還沒算圖節點的 metadata。開一臺 128 GB RAM 的機器頂多撐到 2000 萬條就得考慮 sharding。

Pinecone、Qdrant 這類專門引擎會把索引拆到 disk-backed 結構,讓 RAM 只放常用熱資料。pgvector 本身沒有這條路徑,這是 pgvectorscale 想補的洞。

StreamingDiskANN 把索引留在硬碟上

pgvectorscale 的核心是移植 Microsoft Research 2019 年提出的 DiskANN 演算法,Bing 圖片搜尋跟 Pinecone 自家的 graph index 都用同一套。概念是把大部分的向量跟連接關係寫到 SSD 上,查詢時只把候選節點串流讀進記憶體。

單看這一項會擔心 SSD 隨機讀寫的延遲被放大,但 pgvectorscale 把 disk layout 排成連續的 page,加上 NVMe 幾十萬 IOPS 的能力,實測下來 p95 延遲反而低於 HNSW 全 in-memory 的表現——Timescale 官方在 5000 萬條向量的 benchmark 拿到 p95 28 毫秒,Pinecone storage-optimized 索引在同樣資料集是 784 毫秒。這個差距不是量級誤差可以解釋的。

值得一提的是 diskann.query_rescore 這個查詢時參數,允許在延遲跟召回率之間拉一條可調的線。對召回率沒那麼敏感的推薦場景可以壓到 10 以下換更快的回應。

Statistical Binary Quantization 為什麼比一般二元量化準

DiskANN 本身還不足以把 Postgres 拉到跟 Pinecone 平起平坐,另一半的關鍵是 pgvectorscale 團隊自家的壓縮方案:Statistical Binary Quantization(SBQ)。

一般的 binary quantization 用 0.0 當閾值,float 大於 0 記成 1、小於 0 記成 0。這種粗暴做法在向量分佈偏斜的資料集上召回率會掉得很難看。SBQ 在建索引時掃一遍整個資料集,對每個維度算出實際的平均值,用平均值當閾值。

實測數字:3072 維的 float32 向量從 12,288 bytes 壓成 384 bytes,32 倍壓縮率下召回率仍有 96 到 99 個百分點。壓縮過的向量常駐記憶體用來做圖上的距離估算,完整向量留在 heap 上,最後再用 rescore 步驟撈原始向量算精確距離。這樣一來單臺機器能撐的向量數量往上跳一個量級。

Label-based filtered search 解掉 metadata 過濾的老問題

pgvector 加 metadata 過濾一直有個結構性缺陷:ANN 索引先跑近似最近鄰、再套 WHERE 條件過濾的順序,會讓 filter 選擇性高的查詢直接掉到 sequential scan。過去要繞過這個問題得靠 partial index 或 partition 這類邏輯層 workaround。

pgvectorscale 把 metadata label 直接編碼進 DiskANN 的圖節點,查詢時同時做距離計算跟 label 匹配。做法源自 Microsoft 2023 年發表的 Filtered DiskANN 論文,適合 multi-tenant 場景或需要按類別、時間段限縮結果的搜尋。

導入 pgvectorscale 的實務路徑

pgvectorscale 需要 pgvector 0.7 以上,架構上兩者互補、不衝突。既有 pgvector 專案切過去只有兩步。

沒現成套件的話,用 Timescale 官方的 Docker 映像檔最快:

1
2
3
4
docker run -d --name pgvs \
-p 5432:5432 \
-e POSTGRES_PASSWORD=xxx \
timescale/timescaledb-ha:pg17-latest

這個 HA 映像檔已經內建 pgvector 跟 pgvectorscale。要從既有 Postgres 加裝,就靠 cargo-pgrx 從原始碼編譯:

1
2
3
cargo install --locked cargo-pgrx --version 0.11.4
cd pgvectorscale
cargo pgrx install --release

在資料庫裡啟用擴充:

1
CREATE EXTENSION IF NOT EXISTS vectorscale CASCADE;

CASCADE 會順便把 pgvector 拉進來。之後建索引改用新的方法名稱:

1
CREATE INDEX ON items USING diskann (embedding vector_cosine_ops);

舊的 HNSW 索引可以先留著並存,觀察一段時間再刪除。實務上小於 100 萬條向量的資料集用 HNSW 反而快,切換不是必然的選項。

什麼樣的專案該現在就切

已經用 pgvector 且資料量在千萬級以上:直接切。RAM 成本會馬上有感下降,查詢延遲也會改善。

在 Pinecone 上每月花超過 200 美元:值得評估自架 Postgres + pgvectorscale。25% 的成本區間對中小型專案是實打實的差距,還順帶把 SQL join、transaction 這些原本要拆到兩套系統的能力收回同一個資料庫。

還在原型階段、資料量沒過 100 萬條:先用 pgvector 加 HNSW 就好。pgvectorscale 的優勢要在規模上才會顯現,過早導入只會增加維運複雜度。

極端規模(十億條向量以上):Postgres 這條路的天花板還在。這種量級 Qdrant、Milvus 這類專門引擎仍然是更務實的選擇。

Postgres 這幾年靠 extension 生態把觸手伸進越來越多過去要靠專門服務的領域,向量搜尋是最新一個被收回來的類別。pgvectorscale 的路線走得很聰明——不去重寫 pgvector,而是在旁邊補上高延展性的索引跟壓縮方案,讓既有的 Postgres 專案可以無痛擴展。

想找一臺穩定的臺灣 VPS 來自架 Postgres 加 pgvectorscale、跑生產級的向量搜尋?NCSE Network 提供搭載 Intel Xeon Gold CPU 跟 NVMe SSD 的 VPS 方案,是方電訊機房本地連線,NVMe 對 DiskANN 這類 disk-backed 索引的隨機讀寫特別關鍵。前往 ncse.tw 了解方案細節。

需要穩定的雲端主機?

NCSE Network 提供企業級 VPS,7 天免費試用,臺灣是方電訊機房,99% SLA 保證。

查看 VPS 方案 →