Ein Gegenargument zu pgvector
(alex-jacobs.com)- Die Postgres-Erweiterung pgvector unterstützt die Vektorsuche nach Ähnlichkeit, aber zwischen Demo-Niveau und realer Produktionsumgebung klafft eine große Lücke
- Sowohl IVFFlat- als auch HNSW-Indizes haben klare Vor- und Nachteile; insbesondere ist bei HNSW der Speicherverbrauch im GB-Bereich beim Indexaufbau sowie die lange Build-Zeit problematisch
- Echtzeitsuche und Indexaktualisierungen sind strukturell schwierig, und bei kontinuierlichen Einfügungen und Updates kommt es zu Lock-Konkurrenz und Leistungseinbußen
- Aufgrund von Filterstrategien (Pre/Post) und den Grenzen des Query Planners entsteht ein instabiles Gleichgewicht zwischen Suchgenauigkeit und Geschwindigkeit
- Funktionen, die dedizierte Vektor-Datenbanken (Pinecone, Weaviate usw.) bereitstellen, müssen manuell nachgebaut werden, was letztlich zu mehr betrieblicher Komplexität und höheren Kosten führt
Überblick über die Grenzen von pgvector
- pgvector ist eine Erweiterung für Postgres, die Vektor-Ähnlichkeitssuche hinzufügt; in einfachen Demos funktioniert sie gut, in Produktionsumgebungen treten jedoch Skalierungsprobleme auf
- Viele Blogbeiträge behandeln nur die Installation und einfache Query-Beispiele, während Probleme bei Performance, Speicher und Indexverwaltung im Betrieb kaum erwähnt werden
Das Problem der Indexwahl
- pgvector bietet zwei Indextypen: IVFFlat und HNSW
- IVFFlat: Cluster-basierte Struktur; der Index lässt sich schnell erstellen, aber die Anzahl der Cluster hat großen Einfluss auf Performance und Genauigkeit
- Da keine Umverteilung der Cluster möglich ist, ist ein regelmäßiger Neuaufbau des Index erforderlich
- HNSW: Mehrschichtige Graphstruktur, die Genauigkeit und konsistente Performance bietet, aber beim Indexaufbau sehr viel Speicher verbraucht und langsam ist
- IVFFlat: Cluster-basierte Struktur; der Index lässt sich schnell erstellen, aber die Anzahl der Cluster hat großen Einfluss auf Performance und Genauigkeit
- Beim Erstellen von Indizes für mehrere Millionen Vektoren können über 10 GB RAM benötigt werden, was die Stabilität der produktiven Datenbank direkt gefährdet
Schwierigkeiten bei der Echtzeitsuche
- Neue Daten sollten nach dem Einfügen sofort durchsuchbar sein, aber aufgrund der Struktur der Indexaktualisierung ist eine Echtzeitübernahme schwierig
- IVFFlat: Neue Vektoren werden bestehenden Clustern hinzugefügt; mit der Zeit entsteht ein Ungleichgewicht der Cluster → periodischer Neuaufbau nötig
- HNSW: Beim Einfügen führt die Aktualisierung des Graphen zu Lock-Konkurrenz und zusätzlicher Speicherlast
- Während eines Neuaufbaus des Index ist es schwierig, Datenkonsistenz und Servicekontinuität sicherzustellen
- In Produktionsumgebungen sind verschiedene Umgehungsstrategien wie Staging-Tabellen, doppelte Indizes, Offline-Builds, eventual consistency usw. erforderlich
Grenzen bei Filterung und Query Planner
- Wenn Metadatenfilter wie
status,user_id,categorymit Vektorsuche kombiniert werden, hat die Wahl zwischen Pre-filter und Post-filter großen Einfluss auf die Performance- Pre-filter ist bei selektiven Filtern vorteilhaft, wird aber bei großen Datenmengen langsam
- Post-filter ist schnell, birgt aber die Möglichkeit, dass nach dem Filtern Ergebnisse fehlen
- Der Query Planner von Postgres versteht das Kostenmodell der Vektor-Ähnlichkeit nicht; ungenaue Statistiken führen zu ineffizienten Ausführungsplänen
- In der Folge sind provisorische Lösungen wie CTEs, Partitionierung und Query-Rewrites nötig, die beim Skalieren ineffizient sind
Vergleich mit dedizierten Vektor-Datenbanken
- Pinecone, Weaviate, OpenSearch k-NN usw. bieten automatische Wahl der Filterstrategie, hybride Suche, Echtzeit-Indexierung und horizontale Skalierung standardmäßig an
- In pgvector müssen diese Funktionen selbst implementiert werden, was zu betrieblicher Komplexität und höherem Wartungsaufwand führt
- Timescales pgvectorscale bietet StreamingDiskANN, inkrementellen Indexaufbau und Verbesserungen bei der Filterung,
- wird jedoch von AWS RDS nicht unterstützt und bringt zusätzlichen Aufwand für Installation und Verwaltung von Erweiterungen mit sich
Kosten- und Betriebsaspekte
- Dedizierte Vektor-DBs sind kostenpflichtige Dienste, aber wenn man Überprovisionierung der Postgres-Infrastruktur, Indexverwaltung und Engineering-Zeit berücksichtigt, können sie in der Praxis günstiger sein
- Als Beispiel startet Turbopuffer bei 64 $ pro Monat und bietet betriebliche Einfachheit und Skalierbarkeit
Fazit und Empfehlungen
- pgvector ist technisch hervorragend, hat in Produktionsumgebungen aber viele Einschränkungen
- Wichtige Punkte beim Aufbau eines produktiven Systems
- Die Komplexität der Indexverwaltung und der hohe Speicherbedarf
- Die Grenzen des Query Planners, die zu ineffizienter Filterung führen
- Die Kosten der Echtzeit-Indexierung und Qualitätsverluste
- Die übermäßige Vereinfachung in Blogbeiträgen
- Warum es dedizierte Vektor-DBs gibt und wie effizient sie sind
- Letztlich ist die betriebliche Komplexität größer als die Einfachheit der Postgres-Integration, und für die meisten Teams ist die Nutzung einer dedizierten Vektor-Datenbank die realistischere Wahl
5 Kommentare
Trotzdem gibt es für zusammengesetzte Abfragen (Embedding + traditionelles SQL) nichts, was an pg_vector herankommt.
Ich denke, damit das Ökosystem gesund bleibt, braucht es auch viele Gegenstimmen zu solchen Allzweck-Erzählungen.
Ich stimme zu. Für Organisationen, die Postgres bereits gut nutzen und mit kleinen Datenmengen eine VectorDB einführen, ist pgVector eindeutig eine ausgezeichnete Wahl. Wenn der Traffic jedoch zunimmt, insbesondere der Write Traffic, scheinen die vom Autor des Originalbeitrags genannten Probleme zum Engpass zu werden.
Stimmt. Nichts ist perfekt. So etwas wie „Es gibt andere dringendere Aufgaben“ ist noch in Ordnung, aber ich finde, man darf „Das aktuelle Niveau ist auch ausreichend“ nicht akzeptieren.
Hacker-News-Kommentar
Wir verwenden pgvector bei Discourse bereits in Tausenden von Datenbanken produktiv.
Es wird für die meisten Pageviews genutzt, und die Funktion Iterative Scans wurde in Version 0.8.0 hinzugefügt, um Probleme mit Pre-/Post-Filtering zu verbessern.
Für einen einzelnen Service mag eine dedizierte Vektor-DB einfacher sein, aber sie ist keine Universallösung.
Für die Speicherung verwenden wir halfvec (16-Bit-Float), für Indizes bit (binäre Vektoren), sodass wir sowohl Speicherkosten als auch Performance optimieren konnten.
Wir verwenden Vespa, um Suchen nach einem Map-Reduce-Ansatz auf Knotenebene auszuführen.
Um etwas Ähnliches in Postgres umzusetzen, wären vermutlich Sharding und komplexe Applikationslogik nötig.
Reindexing oder die Denormalisierung von Metadaten würden zwangsläufig viel Zeit kosten.
Trotzdem sind Vektor-DBs keine Universallösung, und Systeme wie Vespa, die relationale Filterung unterstützen, sind deutlich effizienter.
Allerdings ist iterative scan keine grundlegende Lösung, sondern eher ein Workaround.
Man muss Parameter wie ef_search und max_search_tuples verstehen, und der Planner versteht das Kostenmodell gefilterter Vektorsuchen nicht vollständig.
Letztlich ist es die Frage, ob man die Kapazität hat, einen smarten Query Planner selbst zu tunen, oder ob man lieber einen Dienst nutzt, der darauf spezialisiert ist.
Die in einem Paper von Microsoft beschriebene Methode wird von Timescales pgvectorscale implementiert.
Dieser Ansatz kann effizienter sein als einfaches Pre-/Post-Filtering.
Wir haben in VectorChord die meisten der im Blog erwähnten Probleme von pgvector gelöst.
Mit IVF + Quantization unterstützen wir 15-mal schnellere Updates als HNSW in pgvector.
Mit 16 vCPU und 32 GB RAM lassen sich 100 Millionen 768-dimensionale Vektoren in 20 Minuten indexieren.
Mit
CREATE INDEX CONCURRENTLYist Reindexing ohne Datenverlust möglich.Pre-/Post-Filtering und hybride Suche auf Basis von BM25 werden ebenfalls unterstützt.
Details finden sich im VectorChord-Blog.
Einen entsprechenden Fall findet man in diesem Blog.
Der Index-Build verbraucht viel Speicher, lässt sich aber über
maintenance_work_memsteuern.Ein Rebuild des Index kann mit
REINDEX CONCURRENTLYdurchgeführt werden, und HNSW-Updates sind konzeptionell ähnlich wie B+tree-Updates.Der Artikel wirkt, als hätte er die Postgres-Dokumentation nicht richtig gelesen.
maintenance_work_membegrenzt, wird das Indexing allerdings langsamer.Ein B+tree fasst nur log-H-Seiten an, HNSW muss aber Tausende von Vektoren ändern.
Um sie neu aufzubauen, muss man die DB-Kapazität auf mehr als das Doppelte erhöhen, und das beeinflusst auch andere Workloads.
Auch
REINDEX CONCURRENTLYdauert lange.Selbst wenn HNSW-Einfügungen eine niedrige Komplexität haben, sind die konstanten Kosten hoch und in der Praxis belastend.
maintenance_work_memgibt, ist es riskant, im laufenden Betrieb über Stunden hinweg RAM im GB-Bereich zu belegen.Auch
REINDEX CONCURRENTLYverbraucht 2- bis 3-mal mehr Disk und beeinflusst die Performance.Entscheidend ist also nicht, dass Postgres Funktionen fehlen, sondern dass die operative Komplexität hoch ist.
Eine dedizierte Vektor-DB übernimmt solche Dinge automatisch und ist für kleine Teams daher deutlich effizienter.
Dass Turbopuffer bei 64 US-Dollar pro Monat startet, erklärt die Beliebtheit von pgvector.
Wenn 64 Dollar teuer wirken, nimmt man pgvector; wenn sie günstig wirken, hat man wahrscheinlich schon einen komplexen Anwendungsfall, für den eine dedizierte Vektor-DB besser passt.
Ich habe auch bei GCP-Kunden viele produktive Einsätze von pgvector HNSW gesehen.
Realistisch ist es aber nur im Bereich von 0 bis 10 Millionen Vektoren.
Man muss ETL, operativen Overhead und Konsistenzprobleme berücksichtigen.
Wenn man Transaktionen, hybride Suche und niedrige Latenz braucht, ist AlloyDB + ScaNN die bessere Wahl.
(Zur Einordnung: Ich habe ScaNN bei GCP gebaut und leite derzeit AlloyDB Semantic Search.)
Mein Grundprinzip ist YAGNI.
Ich reduziere die Anzahl der Services so weit wie möglich und füge erst dann etwas Neues hinzu, wenn wirklich Probleme auftreten.
Wenn Postgres ausreicht, bleibe ich dabei; wenn nicht, weiß ich dann zumindest genau, was ich brauche.
Dinge wie Echtzeit-Vektor-Schreibvorgänge oder die Kombination aus SQL-Filtern und Ähnlichkeitssuche wirken trivial, sind in Wirklichkeit aber essenzielle Funktionen.
Mit wachsender Größenordnung treten solche Einschränkungen fatal zutage.
Beim Einsatz von Vektor-Embedding-Modellen gibt es auch ohne riesige Datensätze viele nützliche Anwendungsfälle.
Etwa Dokumentensuche oder Produktsuche.
Ich hätte gern eine Art Dateisystem-ähnliche Oberfläche, bei der sich der Index automatisch aktualisiert, wenn man Dokumente schreibt.
Deshalb finde ich Dienste wie Amazon S3 Vectors(Link) interessant.
Mich würden praktische Erfahrungen damit interessieren.
Ein passendes Tutorial gibt es in diesem Artikel.
Die genannten Probleme sind bereits gelöst, und ich nutze PGVector lieber.
Wenn Postgres Kafka ersetzen und 100.000 Events pro Sekunde verarbeiten kann, dann sollte auch PGVector statt einer dedizierten Vektor-DB wie Chroma absolut ausreichen.
Referenzlink
Die meisten pgvector-Anwendungsfälle sind kleine Datensätze wie ein „Chatbot auf Basis technischer Dokumentation“.
Die Daten ändern sich nicht häufig, und es gibt kein Multi-Tenancy, daher sind auch die Filterprobleme geringer.
Chroma unterstützt dagegen SPANN, SPFresh und hybride Suche und ist vollständig Open Source unter Apache 2.0.
Mit nutzungsbasierter Abrechnung sind sogar Kosten im Bereich von 1 US-Dollar pro Monat möglich.
Ich habe im letzten Jahr entwickelte Redis Vector Sets genau für diese Probleme gebaut.
Durch eine eigene HNSW-Implementierung sind Echtzeit-Updates möglich, und beim Löschen wird Speicher sofort wieder freigegeben.
Unterstützt werden Einfügegeschwindigkeiten von mehreren hunderttausend Ops/Sek. und Suchgeschwindigkeiten von 50.000 Ops/Sek.
Quantization wird standardmäßig unterstützt, was auch die Speichereffizienz verbessert.
Im README habe ich alles ausführlich dokumentiert.
Inzwischen ist auch die Replikationsfunktion vollständig getestet.