1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「どのベクトルDBがいい?」に「場合による」で逃げないRAGを作った

1
Last updated at Posted at 2026-07-11

RAG を作るとき、最初の質問はたいてい「ベクトル DB はどれにしますか?」です。私はこれに「場合による」と答え続けてきました。正しいけれど、何の役にも立ちません。そこで、「場合による」の中身を実測データで答える RAG を作ることにしました。rag-db-advisor です。Claude Code から MCP 経由で「10 万件・日本語・更新頻度高めならどの DB?」と聞くと、実測値を根拠つきで返します。

問題は、その「実測データ」でした。既存の比較記事の多くは機能表かベンダー公表値で、検索品質を人手の正解データで測った再現可能な一次データは見つかりませんでした。ないので、作りました。7 製品 9 構成を同一条件で測るハーネス rag-retriever-bench です。対象は pgvector、ClickHouse(3 構成)、Qdrant、Weaviate、Milvus、Chroma、LanceDB。

結論を先に置きます。検索品質はほぼ同着でした。差が出たのはレイテンシの固定費構造、書き込みの速さ、そして運用の罠の数です。特に 3 つ目が強烈で、7 製品中 3 製品が、エラーを一切出さずに劣化する挙動を踏みました。この記事はその一部始終です。

先にゴール: 実測データに答えさせる RAG

完成形から見せます。

claude mcp add rag-db-advisor -- rag-db-advisor mcp

MCP サーバーとして動き、Claude Code や Claude Desktop から DB 選定・チューニングの質問を投げられます。ツールは advise(実測ベースの根拠)、compare_backends(規模別の比較表)、list_traps(踏んだ罠のカタログ)の 3 つ。回答の合成はクライアント側の LLM がやるので、サーバー側に生成用の API キーは要りません。

こだわりは 2 つです。1 つ目、知識源は自分の実測と運用ノートだけ。回答の数値はすべて後述のベンチマークに由来し、出典つきで返ります。ハルシネーションの入り口を構造的に塞ぎました。

2 つ目、検索層はベンチマークの抽象化をそのまま import しています。では advisor 自身はどの DB を選んだかというと、Chroma の embedded です。数百チャンク規模では品質が同着なので、運用が一番軽いものを選ぶ。アドバイザーが自分の助言に従っている構図です。作った本人が言うのも変ですが、ここが一番気に入っています。

あとはこの RAG に食わせる「実測データ」を作るだけです。ここからが本編で、全体の 9 割の時間はこちらに溶けました。

知識源がないなら測る

条件を固定してデータベースだけを差し替えるハーネスを書きました。

  • データ: MIRACL(ja) — 日本語 Wikipedia パッセージ + 人手の正解判定。860 クエリ、コーパス 1 万 / 10 万件
  • 埋め込み: text-embedding-3-small を全構成共通。10 万件で $0.30(一番高くついたのは埋め込み代ではなく、後述の罠で溶けた時間でした)
  • インデックス: HNSW パラメータを全構成で統一。差が出たらエンジンの差で、チューニングの差ではありません
  • 指標: recall / nDCG / MRR@10 とレイテンシ p50/p95/p99、取り込み・構築時間。LLM-as-judge は使わないので、何回走らせても同じ意味の数字が出ます

バックエンドは小さなインターフェース(setup / load / build_index / search)の実装だけで追加できます。1 バックエンド 1 ファイルです。

結果 1: 検索品質で DB を選ぶ意味は(ほぼ)ない

10 万件・9 構成の全体像です。

9構成の実測結果

HNSW 勢 7 構成の recall@10 は 0.921〜0.947 に収束しました。1 万件だと 0.976〜0.983 で、さらに団子です。順位表を作るつもりで 9 個測ったら、表彰台に全員乗ってしまいました。「精度が高いベクトル DB はどれか」という比較軸は、実測すると成立しませんでした。

例外は量子化です。

量子化のrecall代償

LanceDB の標準インデックスは HNSW に 8bit スカラー量子化を重ねたもので、recall@10 は 1 万件 0.901、10 万件 0.811。素の HNSW 勢との差は 8 ポイントから 12 ポイントへ、スケールで拡大します。見るべきは「HNSW と書いてあるか」ではなく「量子化が入るか」でした。

結果 2: レイテンシはアーキテクチャの固定費で決まる

10 万件の検索 p50 は、専用ベクトル DB 勢(Weaviate 1.8ms / Milvus 2.0ms / Qdrant 3.3ms)が最速帯、pgvector が 4.8ms、ClickHouse はデフォルト設定だと 43.1ms でした。

granule読み増幅

ClickHouse だけ桁が違う理由は、列指向ならではの読み出し増幅でした。HNSW が返す候補は行ではなく「granule(行のブロック)」で、再スコアリングでブロック丸ごと読みます。index_granularity を 8192 から 128 に絞ると読む行数が 64 分の 1 になり、p50 は 43.1ms → 11.5ms。設定 1 つで 3.7 倍です(recall への影響はラン間ノイズ程度でした)。

結果 3: 書き込み側はしばしば検索より効く

書き込み側の比較

10 万件の取り込み + インデックス構築は ClickHouse 約 20 秒、pgvector 約 56 秒。検索 p50 の数 ms 差より、この 36 秒差のほうが効く設計は珍しくありません。毎晩コーパスを作り直す RAG なら書き込み側を、一度作って読むだけなら検索側を見る。重視すべき軸は更新頻度が決めます。

本題: エラーなしで劣化した 3 つ

ここからが一番書きたかった部分です。構築の過程で、7 製品中 3 製品が「エラーではなく、品質かレイテンシの劣化」として壊れました。

ClickHouse: allow_experimental_vector_similarity_index = 1 はクエリ実行時にも必要で、付け忘れると HNSW のつもりの検索が黙ってフルスキャンになります。発覚したのは「HNSW が 27ms、brute force が 31ms でほぼ同じ」という不自然な数字から。「ClickHouse は HNSW でもこの速さなのか」と結論しかけていたので、危ないところでした。

Qdrant: デフォルトでは 20MB 未満のセグメントを索引化しません。ステータスは green のまま索引ゼロで、860 クエリ全部がフルスキャンでした。この green は「問題ありません」ではなく「やることがありません」の緑です。小さいデータで検証してから本番へ、という常識的な手順が、検証段階だけインデックスなしという罠になります。

Milvus: 2 段構えでした。quick-setup はインデックス指定を黙って捨てて AUTOINDEX を作ります。それを直しても、ロード済みスナップショットが新しいセグメントを含まず、search は「見えている分だけ」から top-10 を返します。recall だけが 0.922 に静かに下がり、全再ロードで 0.980 に戻りました。

共通するのは、失敗がエラーではなく数字の劣化として現れることです。劣化した数字は、比較対象がなければ「そういう性能」に見えてしまいます。

対策として、ハーネスに self_check という機構を入れました。EXPLAIN やサーバー統計で「ANN インデックスが本当に使われているか」を機械検証し、レポートに記録します。ちなみにクエリプランで確認できるのは pgvector と ClickHouse だけで、残りはサーバー統計か設定値まで。プランを見せてくれる DB は、それだけで運用上の価値があります。

ほかにも、1 万件では出ず 10 万件で初めて出る罠(pgvector の並列インデックス構築が要求する 2.1GB の共有メモリ、ClickHouse の挿入時タイムアウト等)をいくつも踏みました。対策込みの罠カタログはリポジトリにまとめてあり、そのまま rag-db-advisor の list_traps の中身になっています。踏んだ罠は、供養すると knowledge base になります。

限界と注意

  • 単一ノード Docker での測定です。分散構成・高負荷並列は対象外
  • データは MIRACL-ja、埋め込みは text-embedding-3-small。別条件では数字が変わります。変わるからこそ、自分のデータで測るためのハーネスを公開しています
  • Chroma / LanceDB は in-process 動作で、サーバー型とレイテンシを直接比較できません(レポートでも表を分けています)
  • HNSW には乱数性があり、recall はラン間で ±0.005 程度揺れます。0.01 未満の差から結論を出すのは危険です

まとめ

  • 「RAG 選定に答える RAG」を作るために、7 製品 9 構成を同一条件で実測した。データと罠カタログは rag-retriever-bench、答えさせる MCP サーバーは rag-db-advisor にあります
  • 同一条件なら HNSW 勢の検索品質はほぼ同着。精度で DB を選ぶ時代は(この規模では)終わっていました。差はレイテンシの固定費、書き込み速度、運用の罠の数に出ます
  • 7 製品中 3 製品が「エラーなしの劣化」で壊れた。インデックスが効いているかは、信じずに検証するが対策です

AI 時代のデータベースに何が変わったかと聞かれたら、私はこう答えます。SQL の正しさはエラーが教えてくれましたが、ベクトル検索の正しさは黙って劣化します。データベースを信頼する方法が、宣言から検証に変わりました。その検証装置ごと公開してあるので、この記事の数字は、私の言葉ではなく再実行で疑ってもらえます。


📘 関連Book

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?