pgvector als RAG-Backbone — wann es reicht und wann du eine dedizierte Vector-DB brauchst

pgvector vs. Qdrant/Pinecone/Weaviate: konkrete Performance-Zahlen, Index-Empfehlungen (IVFFlat vs HNSW), Skalierungsgrenzen und Migration-Pfade. Plus warum die meisten Projekte mit pgvector bestens fahren.

19. Mai 202610 min Lesezeit889 Wörter

Die Frage, die alle stellen

Bei jedem zweiten KI-Projekt landet diese Diskussion im Stack-Review-Meeting: „Brauchen wir nicht eine richtige Vector-DB? Qdrant? Pinecone?"

Die ehrliche Antwort: In 90 % der Projekte reicht pgvector. Aber die letzten 10 % können bei Skalierung schmerzhaft werden. Hier die Entscheidungsmatrix mit echten Zahlen.

Was pgvector ist und wie es funktioniert

pgvector ist eine Postgres-Extension, die vier Dinge hinzufügt:

  1. Den vector(N)-Datentyp (z. B. vector(1536) für OpenAI-Embeddings)
  2. Distance-Operatoren: <-> (L2), <=> (Cosine), <#> (inner product)
  3. Approximate-Index-Typen: IVFFlat und HNSW
  4. Standard-SQL-Integration — Joins mit relationalen Tabellen möglich

Aktivieren auf self-hosted Supabase:

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE knowledge_chunks (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  doc_id uuid NOT NULL REFERENCES documents(id),
  content text NOT NULL,
  embedding vector(1536) NOT NULL,
  metadata jsonb DEFAULT '{}'::jsonb
);

-- HNSW-Index für Cosine-Similarity
CREATE INDEX knowledge_chunks_embedding_idx
  ON knowledge_chunks
  USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 64);

Query:

SELECT content, 1 - (embedding <=> $1::vector) AS similarity
FROM knowledge_chunks
WHERE 1 - (embedding <=> $1::vector) > 0.7
ORDER BY embedding <=> $1::vector
LIMIT 10;

IVFFlat vs. HNSW — Cheatsheet

IndexBuild-TimeQuery-LatenzRecallBest für
IVFFlatschnell (~1 min/1M Vektoren)mittel (10–30 ms)mittel (90–95 %)< 1M Vektoren, viel Insert/Update
HNSWlangsam (~10 min/1M)schnell (1–5 ms)hoch (98–99 %)Read-heavy, < 10M Vektoren
kein Indexn/alangsam (linear)100 %< 10k Vektoren

Default-Empfehlung 2026: HNSW. Build-Zeit ist einmalig, Query-Performance dauerhaft besser. IVFFlat nur wenn du wirklich viele Inserts pro Sekunde hast.

Performance-Zahlen aus der Praxis

Setup: Hetzner CX42 (8 vCPU, 16 GB RAM), Postgres 17, ~500.000 Chunks à 1536-dim:

  • Insert + Index-Build: ~8 Minuten initial
  • Query mit HNSW: 3–7 ms p50, 15 ms p99
  • Query ohne Index (linear): ~280 ms — unbrauchbar

Bei 5 Millionen Chunks auf gleicher Hardware:

  • HNSW-Index belegt ~12 GB RAM
  • Query-Latenz: 8–15 ms p50, 35 ms p99
  • Konkurrenz mit anderen Postgres-Queries spürbar — Read-Replica nutzen

Ab ~10 Millionen Vektoren wird's eng auf einer einzelnen Maschine. Dann beginnt die Diskussion über dedizierte Vector-DBs.

Wann pgvector klar gewinnt

  1. Joins mit relationalen Daten — du willst Embeddings + Permission-Check + Metadata-Filter in einer Query:

    SELECT c.content, ...
    FROM knowledge_chunks c
    JOIN documents d ON c.doc_id = d.id
    WHERE d.tenant_id = $tenant
      AND d.is_published = true
      AND c.embedding <=> $query < 0.3
    LIMIT 10;
    

    In einer dedizierten Vector-DB müsstest du das in zwei Schritten mit Application-Logik machen — langsamer und fehleranfälliger.

  2. Multi-Tenant mit RLS — vector-Column kann RLS-protected sein wie jede andere Column. In Qdrant/Pinecone musst du Tenant-Isolation selbst bauen.

  3. Konsistenz mit Source-of-Truth — Embeddings im gleichen DB-Backup wie Quelldaten. Nie aus dem Sync.

  4. Kosten — pgvector ist kostenlos, läuft auf existierendem Postgres. Pinecone startet bei ~70 $/Monat für die Starter-Tier, Qdrant Cloud bei ~25 $/Monat.

Wann eine dedizierte Vector-DB lohnt

  1. > 10M Vektoren oder hochfrequentes Re-Indexing — pgvector skaliert vertikal (mehr RAM), Qdrant/Weaviate skalieren horizontal (Sharding) sauberer.

  2. Hybrid Search out-of-the-box — Qdrant, Weaviate haben native BM25 + Vector-Combo. In pgvector musst du das mit tsvector selbst bauen (geht, aber Arbeit).

  3. Spezielle Quantisierungs-Features — Qdrant unterstützt int8/binary-Quantisierung native, was Memory um 4–32× reduziert.

  4. Multi-Modal mit unterschiedlichen Dimensionen — wenn du Text-Embeddings (1536d), Image-Embeddings (768d), Audio-Embeddings (512d) parallel hast, sind dedizierte DBs einfacher.

Migration-Pfad von pgvector → Qdrant

Wenn pgvector irgendwann nicht mehr reicht, ist Migration straightforward:

# Bulk-Export aus Postgres
import psycopg, qdrant_client
qc = qdrant_client.QdrantClient(url=QDRANT_URL)
qc.create_collection("knowledge", vectors_config={"size": 1536, "distance": "Cosine"})

with psycopg.connect(PG_URL) as conn:
    cur = conn.cursor()
    cur.execute("SELECT id, embedding, content, metadata FROM knowledge_chunks")
    batch = []
    for id, emb, content, meta in cur:
        batch.append(qdrant_client.PointStruct(
            id=str(id), vector=emb,
            payload={"content": content, **meta}
        ))
        if len(batch) >= 1000:
            qc.upsert("knowledge", points=batch)
            batch = []
    if batch: qc.upsert("knowledge", points=batch)

In meinen Projekten: 1–2 Tage für die Migration, inklusive Test der neuen Such-Latenz.

Pitfalls aus der Praxis

  • ef_search nicht getuned — der wichtigste HNSW-Query-Parameter. Standard ist 40, höher = genauer aber langsamer. Setze ihn pro Query: SET LOCAL hnsw.ef_search = 100;
  • Embeddings vor Index hinzufügen — beim Bulk-Import erst Daten laden, DANN Index erstellen. Sonst wird der Index für jeden Insert mit aktualisiert = 100× langsamer.
  • Kein VACUUM nach großem Update — Postgres-Statistiken werden veraltet, der Planner wählt schlechte Pläne. VACUUM ANALYZE knowledge_chunks nach großen Updates.
  • Cosine vs L2-Distance verwechselt — OpenAI-Embeddings sind normalisiert, d. h. Cosine und L2 geben andere Ranking-Reihenfolgen. Immer vector_cosine_ops für OpenAI nehmen.

Embedding-Modell wählen

ModellDimKontextKosten/1M TokQuality
text-embedding-3-small (OpenAI)1536 (oder 512 truncated)81920.02 $sehr gut
text-embedding-3-large (OpenAI)307281920.13 $ausgezeichnet
bge-m3 (BAAI, lokal)102481920sehr gut, multilingual
nomic-embed-text-v1.5 (lokal)76881920gut, schnell

Empfehlung: text-embedding-3-small für Cloud-Setups, bge-m3 für On-Prem. large nur wenn small qualitativ nicht reicht (selten).

Nächste Schritte

Bei Bedarf an einem RAG-Setup für deine Knowledge-Base mit konkreten Performance-Garantien: Anfrage.

In Praxis

Verwandte Artikel

Neue Artikel via RSS abonnieren