- Postgres拡張 pgvector はベクトル類似検索をサポートするが、デモレベルと実運用環境のギャップが大きい
- IVFFlat と HNSW インデックス にはそれぞれ明確な長所と短所があり、特に HNSW は インデックス作成時に数GB単位のメモリ使用 と長いビルド時間が問題となる
- リアルタイム検索とインデックス更新 は構造的に難しく、継続的な挿入・更新時には ロック競合と性能低下 が発生する
- フィルタリング戦略(Pre/Post) とクエリプランナーの限界により、検索精度と速度の不安定なバランス が生じる
- 専用ベクトルデータベース(Pinecone、Weaviate など) が提供する機能を手動で実装する必要があり、結果として 運用の複雑さとコスト増加 につながる
pgvectorの限界の概要
- pgvector は Postgres に ベクトル類似検索機能 を追加する拡張であり、単純なデモではうまく動作するが、運用環境ではスケーラビリティの問題 が発生する
- 多くのブログ記事はインストールと簡単なクエリ例だけを扱っており、運用時に発生する性能・メモリ・インデックス管理の問題 にはほとんど触れていない
インデックス選択の問題
- pgvector は IVFFlat と HNSW の2種類のインデックスタイプを提供する
- IVFFlat: クラスタベースの構造で、インデックス作成速度は速いが、クラスタ数の設定が性能と精度に大きく影響 する
- クラスタの再配分ができないため、定期的なインデックス再構築が必要
- HNSW: 多層グラフ構造で 精度と一貫した性能 を提供するが、インデックス作成時のメモリ使用量が非常に大きく、速度も遅い
- 数百万件のベクトルインデックス作成時には 10GB以上のRAMを使用 する可能性があり、これは 運用DBの安定性に対する直接的な脅威 となる
リアルタイム検索の難しさ
- 新しいデータを挿入した直後に検索可能である必要があるが、インデックス更新構造上、リアルタイム反映が難しい
- IVFFlat: 新しいベクトルが既存クラスタに追加され、時間の経過とともに クラスタの不均衡 が発生 → 定期的なリビルドが必要
- HNSW: 挿入時のグラフ更新により ロック競合とメモリ負荷 が発生
- インデックス再構築中は データ整合性の維持とサービス継続性の確保が難しい
- 運用環境では ステージングテーブル、二重インデックス、オフラインビルド、eventual consistency など、さまざまな回避戦略が必要になる
フィルタリングとクエリプランナーの限界
status、user_id、category などの メタデータフィルタリング とベクトル検索を組み合わせる際、Pre-filter vs Post-filter の選択が性能に大きく影響する
- Pre-filter は選択性の高いフィルタに有利だが、データ量が多い場合は遅い
- Post-filter は速いが、フィルタ後に結果が欠落 する可能性がある
- Postgres のクエリプランナーは ベクトル類似度のコストモデルを理解できず、統計情報も不正確なため、非効率な実行計画 を生成する
- その結果、CTE、パーティショニング、クエリ書き換えなどのその場しのぎの解決策 が必要になり、これは スケール時に非効率 である
専用ベクトルデータベースとの比較
- Pinecone、Weaviate、OpenSearch k-NN などは、フィルタリング戦略の自動選択、ハイブリッド検索、リアルタイムインデクシング、水平スケーリング を標準で提供する
- pgvector ではこれらの機能を 自前で実装する必要があり、それが 運用の複雑さと保守負担 につながる
- Timescale の pgvectorscale は StreamingDiskANN、増分インデックスビルド、フィルタリング改善などを提供するが、
- AWS RDS では未サポート であり、追加拡張の導入と管理負担 がある
コストと運用面の考慮
- 専用ベクトルDBは有料サービスだが、Postgres インフラの過剰プロビジョニング・インデックス管理・エンジニアリング工数 を考慮すると、実質的にはより安くなる可能性 がある
- 例として Turbopuffer は月額 $64 から利用でき、運用の単純さとスケーラビリティ を提供する
結論と推奨事項
- pgvector は 技術的には優れているが、運用環境では制約が多い
- 運用システム構築時に考慮すべき主なポイント
- インデックス管理の複雑さ と高いメモリ要求
- クエリプランナーの限界 によるフィルタリングの非効率
- リアルタイムインデクシングのコスト と品質低下
- ブログ記事の過度な単純化
- 専用ベクトルDBが存在する理由 とその効率性
- 結論として、Postgres 統合の単純さよりも運用の複雑さのほうが大きく、ほとんどのチームにとっては 専用ベクトルデータベースの利用が現実的な選択 である
5件のコメント
それでも複合クエリ(埋め込み+従来のSQL)では、
pg_vectorにかなうものはない。エコシステムが健全になるためには、万能論に対する反論も多くあるべきだと思います。
同意します。既存で Postgres をうまく使っていた組織が、小規模なデータで VectorDB を始める状況では pgVector が優れた選択肢であることは間違いありませんが、トラフィック(特に Write Traffic)が増えてくる場合には、元記事の著者が述べた問題がボトルネックになるようです。
その通りです。完璧なものはないのですから。"ほかにもっと差し迫った仕事がある"程度ならまだしも、"現状のレベルでも十分だ"という考えを容認してはいけないと思います。
Hacker Newsの意見
私たちはDiscourseですでに数千のデータベースで pgvector を本番環境運用している。
ほとんどのページビューで使われており、Iterative Scans 機能は バージョン 0.8.0 で追加され、pre/post フィルタリングの問題を改善した。
単一サービスなら専用ベクターDBのほうが簡単かもしれないが、それが万能な解決策というわけではない。
保存には halfvec(16bit float)、インデックスには bit(binary vectors)を使い、保存コストと性能の両方を確保している。
Vespa を使ってノード単位の map-reduce 方式で検索している。
Postgres で似たことをやるには、シャーディングと複雑なアプリケーションロジックが必要になりそうだ。
再インデックスやメタデータの非正規化にはどうしても時間がかかると思う。
それでもベクターDBが万能なわけではなく、Vespa のようにリレーショナルなフィルタリングをサポートするシステムのほうがはるかに効率的だ。
ただし iterative scan は根本的な解決策ではなく、応急処置に近い。
ef_search、max_search_tuples のようなパラメータを理解する必要があり、planner もフィルタ済みベクトル検索のコストモデルを完全には理解していない。
結局のところ、賢いクエリプランナーを自分でチューニングする余力があるか、それともそれを専門に扱うサービスを使うかの問題だ。
Microsoft の 論文 で説明されている手法を、Timescale の pgvectorscale が実装している。
この方式は単純な pre/post フィルタリングより効率的な可能性がある。
私たちは VectorChord で、ブログで言及されていた pgvector の問題の大半を解決した。
IVF + quantization を使い、pgvector の HNSW より 15倍高速な更新 をサポートしている。
16vCPU、32GB メモリで 1億件の 768 次元ベクトルを 20 分でインデックス化できる。
CREATE INDEX CONCURRENTLYにより、データ損失なしで再インデックス化できる。pre/post フィルタリングと BM25 ベースのハイブリッド検索もサポートしている。
詳細は VectorChord ブログ を参照。
関連事例は このブログ で確認できる。
インデックス構築はメモリを多く使うが、
maintenance_work_memで制御できる。インデックス再構築は
REINDEX CONCURRENTLYで処理でき、HNSW の更新は B+tree の更新と似た概念だ。この記事は Postgres のドキュメントをきちんと読んでいないような印象を受ける。
maintenance_work_memを制限すると、インデックス作成は遅くなる。B+tree は log H ページしか触らないが、HNSW は数千のベクトルを修正しなければならない。
これを再構築するには DB 容量を2倍以上確保する必要があり、他のワークロードにも影響する。
REINDEX CONCURRENTLYでも時間はかかる。HNSW への挿入は計算量が低くても定数コストが大きく、実際には負担が大きい。
maintenance_work_memのような設定があっても、本番運用中に GB 単位の RAM を何時間も占有するのは危険だ。REINDEX CONCURRENTLYもディスクを 2〜3 倍余計に使い、性能に影響を与える。結局、Postgres の機能が足りないのではなく、運用の複雑さが大きいことが本質だ。
専用ベクターDBはこうしたことを自動で処理するので、小規模チームならはるかに効率的だ。
Turbopuffer が月額 64 ドルから始まるという点が、pgvector の人気を説明している。
64 ドルを高いと感じるなら pgvector を使えばよいし、安いと感じるなら、すでに複雑なユースケースなので専用ベクターDBのほうが適している。
GCP の顧客の中でも、pgvector HNSW を本番で使っている事例を多く見てきた。
ただし現実的なのは 0〜1000 万ベクトル規模までだ。
ETL、運用オーバーヘッド、一貫性の問題などを考慮する必要がある。
トランザクション、ハイブリッド検索、低レイテンシが必要なら AlloyDB + ScaNN のほうがよい選択だ。
(ちなみに私は GCP で ScaNN を作り、現在は AlloyDB Semantic Search を率いている。)
私の基本原則は YAGNI だ。
できる限りサービス数を減らし、問題が起きたらその時点で新しいものを追加する。
Postgres で十分ならそのまま使い、だめならその時に何が必要かを正確に理解できる。
リアルタイムなベクトル書き込み、SQL フィルタと類似度検索の組み合わせのようなものは些細に見えても、実際には必須機能だ。
規模が大きくなると、こうした制約が致命的に表面化する。
ベクトル埋め込みモデルは、大規模データセットでなくても有用なことが多い。
たとえば 文書検索 や 製品情報検索 のようなケースだ。
私は、ファイルシステムのように文書を書けば自動でインデックスが更新されるインターフェースを求めている。
そのため Amazon S3 Vectors(リンク)のようなサービスには興味がある。
実際の使用体験が気になる。
関連チュートリアルは この記事 を参照。
言及されている問題はすでに解決されていて、私は PGVector を使うほうを好む。
Postgres が Kafka を置き換えて毎秒 10 万イベントを処理できるなら、Chroma のような専用ベクターDBの代わりに PGVector でも十分可能だ。
参考リンク
pgvector のユースケースの大半は、「技術文書ベースのチャットボット」のような小規模データセットだ。
データは頻繁に変わらず、マルチテナンシーもないため、フィルタリングの問題も少ない。
一方 Chroma は SPANN、SPFresh、ハイブリッド検索をサポートし、完全な Apache 2.0 オープンソースだ。
従量課金制で、月 1 ドル程度のコストでも利用できる。
私がこの 1 年で開発してきた Redis Vector Sets は、こうした問題を解決する。
HNSW を自前実装して リアルタイム更新 を可能にし、削除時のメモリも即座に回収される。
毎秒数十万 ops の挿入、毎秒 5 万 ops の検索速度をサポートする。
標準で quantization をサポートしており、メモリ効率も高い。
詳細は README ドキュメント にまとめてある。
現在はレプリケーション機能のテストも完全に完了している。