Engineering

pgvectorの限界を1M vectorsで実測してみた話

pgvectorは小規模ベクトル検索に便利だが、どこから専用エンジンが必要になるのか。Rust製エンジン・FAISS・Qdrantと比較しながら、境界線を数字で示します。

結論から言うと、pgvectorは悪くない。ただし「十分」の範囲が思ったより狭い、という話です。

GitHubで何度も見かけるコメントがあります。「pgvector使えばよくない?」。気持ちはわかります。大抵のスタックでPostgresはもう動いている。pgvectorなら新しいサービスなしでベクトル検索が入る。トランザクション整合性もタダで付いてくる。運用が楽。

というわけで、私たちのRust製エンジンとFAISS、Qdrant、pgvectorを実際に比較してみました。性能差の境界がどこにあるか、数字で見ていきます。

pgvectorって何なのか

pgvectorはPostgresの拡張です。vectorカラム型、HNSWインデックス(0.5.0以降)、あとIVFFlatが使えます。クエリはPostgresプロセスの中で走るので、リレーショナルテーブルとのJOINがそのまま書ける。トランザクションセマンティクスも完全。

これが嬉しいのは、2つ目のサービスを立てなくて済むところです。バックアップ、監視、運用手順書が1つで済む。実際、私たちもメタデータ保存と小規模な検索用途にはpgvectorを使っています。

ただし、pgvectorは専用のベクトルストアではありません。HNSWインデックスは共有メモリに載る。Quantizationがない。Postgresインスタンスに来る他のクエリと全部リソースを奪い合う。小規模なら問題にならないけれど、大規模になると積み重なってしんどくなります。

検証環境

ベンチマークの条件は以下の通りです。

  • Vectors: 1M、dim=1024
  • 検索: top-10、single-thread
  • HNSW: M=32、efSearch=50
  • Hardware: Apple M5 Pro

pgvectorの数値は同等条件での公開ベンチマークから引用しています(私たちが今回直接計測した値ではありません)。他のレポートとも一致しています。

ベンチマーク結果

Enginep50 (us)p95 (us)p99 (us)QPSMemory
Schift Engine (SQ8+HNSW)2773925023,4001,024 MB
FAISS HNSW (in-memory reference)6219411,6531,5034,096 MB
Qdrant (local, from our bench)~2,400~350varies
pgvector HNSW (reported, 1M scale)~65,000+~15~4,096 MB

ここで注目すべきは、pgvectorとFAISSのp50差が約100倍、QPSも約100倍あるところです。私たちのエンジンとの差はさらに開いて、225倍以上になります。

Qdrantはローカルで8.7xから9.8x遅い結果でした。HTTPオーバーヘッドと汎用ストレージレイヤーを持つフルサービスなので、これは想定内です。FAISSが一番フェアなHNSW同士の比較で、私たちのSQ8実装はp50で2.3x速く、p99テールは3.3xタイト、メモリは4分の1です。

なぜ専用エンジンが速いのか

性能差の理由は割とシンプルで、汎用DB拡張では取りにくいエンジニアリング上の判断がいくつかあります。

Quantization。 私たちのエンジンはデフォルトでSQ8を使います。1M vectorsでメモリを4,096 MBから1,024 MBに圧縮。Recall@10の低下はたった1.6ポイント(0.9960 -> 0.9800)。一方pgvectorは生のF32で保存するので、dim=1024の1M vectorsだと共有メモリに4 GB。リレーショナルワークロードと競合します。

Memory-mapped storage。 セグメントをmemory-mappedファイルにして、compactionとpreloadを分離しています。ベクトルアクセスパターン専用の設計なので、row storageやMVCCやWALのOLTP向けオーバーヘッドがありません。

SIMD scoring。 ストレージレイアウトからスコアリングまで一つのワークロード向けに設計されていると、SIMD命令を積極的に使えます。Postgresのshared-nothingクエリエグゼキュータの中だと、その余地が限られる。

pgvectorが本当に強いところ

ぶっちゃけ、pgvectorの運用上の利点は本物です。性能差だけで判断するのはフェアじゃない。

  • 追加インフラゼロ。 デプロイ、監視、バックアップの対象が増えない。
  • トランザクション整合性。 ベクトルinsertとメタデータ更新がアトミック。結果整合性のエッジケースがない。
  • JOIN。 ユーザーID、ドキュメントステータス、何でも1クエリでフィルタできる。別のフェッチステップ不要。
  • チームの既存知見。 Postgresを知っていればすぐ使える。新しいクエリ言語も運用モデルも障害モードも学ばなくていい。
  • エコシステム。 psycopg2SQLAlchemyPrismaDrizzle、全部そのまま動く。

小規模なら、これらの利点に実際のコスト削減効果があります。2つ目のステートフルサービスを避けられるopsチームは、運用が楽なチームです。

どこからが専用エンジンの領域なのか?

pgvector vs 専用エンジン」という二項対立は正しくなくて、本当の問いは「pgvectorの制約がプロダクトに影響し始めるのはどの時点か」です。

ScaleQPS要件レイテンシ要件判定
100K vectors未満Single-digit QPS100ms許容pgvectorで正解
100K-500K vectors50 QPS以下Sub-100ms許容pgvectorで動く。メモリ増加に注意
100K-500K vectors100 QPS超 or sub-10ms必要Sub-10ms必要専用エンジンが有利
500K vectors超プロダクションQPSSub-ms必要専用エンジン一択
任意のスケール任意のQPSリレーショナルJOINが頻繁pgvectorが運用コストでペイ

この結果から分かることは、ほとんどのチームの判断ポイントが100Kから500Kの中間帯にあるということです。それ以下ならpgvectorで間違いない。500K超でまとまったQPSが必要なら、性能差は無視できない。中間帯は、運用のシンプルさと検索性能の本当のトレードオフです。

つまり、200K vectorsで20 QPSの検索機能を2人チームで運用しているならpgvectorが正解。800Kのカスタマー向けベクトルで500 QPSのsub-100ms検索が必要なチームには向かない。

Schiftではどう使い分けているか

私たちは両方使っています。外交的な曖昧回答ではなく、実際のアーキテクチャです。

Postgres(pgvector付き) がメタデータを全て持っています。コレクション設定、ドキュメントレコード、ユーザーデータ、課金状態、組織階層。トランザクション整合性が検索レイテンシより重要な低スケール内部検索にもpgvectorを使っています。

Rustエンジン がカスタマー向けベクトル検索を全部処理します。SQ8+HNSWで、セグメントをmemory-mapし、1M vectorsで277us p50、3,400 QPS。ユーザーアカウントや課金のことは何も知らない。聞かれるのは「このクエリベクトルのtop-k最近傍は?」だけ。

境界は明確で、ベクトル結果とリレーショナルデータのJOINが必要なときは、エンジンで検索してからPostgresでJOINします。pgvectorに重いベクトル処理を頼むことはありません。

225xという数字について

pgvectorが専用エンジンに対して225xから751x遅いと書きました。正確には、この範囲は公開サードパーティベンチマークの異なる条件・ハードウェア・pgvectorバージョンを反映しています。1つの制御テストで出した数字ではありません。

私たちが直接計測したのは、Schift Engine vs FAISSの1M vectors比較です。p50で2.3x速い。p99で3.3xタイト。メモリ4分の1。単一マシンで実インデックスデータを使った自社ベンチスイートの結果です。

FAISSが最もフェアなHNSW同士の比較になります。QdrantのサービスオーバーヘッドもpgvectorのPostgresオーバーヘッドもない。

ちなみに計算はこうです。1M vectorsでpgvectorがFAISSよりレイテンシ約100x遅い(公開ベンチマークと一致)。私たちがFAISSより2.3x速い。だからpgvectorは私たちのエンジンより約225x遅い。算数です。インフラの判断を下す前に、ご自身のデータ分布とハードウェアでベンチマークを回してみてください。

今後の話

Schift Execution Pipelineのセルフホスト用Terraformモジュールを開発中です。専用の検索性能が欲しいけど全部自社クラウドに置きたいチーム向け。エンジン、Quantization、HNSW実装はSchift Cloudで動いているものと同一です。

メタデータ保存には引き続きpgvectorを使います。それは変わりません。Postgresを置き換えたいわけではなく、それぞれの仕事に合ったツールを使うだけです。

Ready to try Schift?

Switch embedding models without re-embedding. Start free.

Get started free