Optimieren Sie PostgreSQL für pgvector
Vektorsuchworkloads stellen im Vergleich zu herkömmlichen transaktions- oder analytischen Abfragen unterschiedliche Anforderungen an PostgreSQL. Wenn Sie diese Unterschiede verstehen, können Sie Konfigurationsparameter optimieren, um die Abfragelatenz, die Speicherauslastung und die Berechnungseffizienz für KI-Anwendungen zu optimieren.
Hinweis
Codebeispiele in dieser Lektion veranschaulichen Konfigurationsmuster für PostgreSQL und pgvector. Die angezeigten Parameterwerte sind Ausgangspunkte für die Optimierung. Optimale Einstellungen hängen von Ihrer spezifischen Workload, Datasetgröße und Hardware ab. Führen Sie immer Benchmarkänderungen in einer Testumgebung durch, bevor Sie sie auf die Produktion anwenden.
Berechnungs- und Speicheranforderungen für Pgvector
Die Vektorähnlichkeitssuche umfasst Computerabstände zwischen einem Abfragevektor und potenziell Millionen von gespeicherten Vektoren. Dieses Rechenmuster unterscheidet sich grundlegend von herkömmlichen Datenbankvorgängen, die Zeilen basierend auf indizierten Spalten filtern oder Tabellen nach Schlüsselwerten verknüpfen.
Wenn Sie eine Vektorähnlichkeitsabfrage ausführen, muss pgvector den Abstand zwischen Dem Abfragevektor und Kandidatenvektoren berechnen. Bei einer 1536-dimensionalen Einbettung (üblich bei OpenAI-Modellen) umfasst jede Entfernungsberechnung 1.536 Gleitkommavorgänge. Für die Suche nach einer Million Vektoren ohne Index sind pro Abfrage mehr als 1,5 Milliarden Gleitkommavorgänge erforderlich. Die drei Entfernungsfunktionen haben unterschiedliche Berechnungskosten, die sich auf Ihre Wahl auswirken, basierend auf Ihren Datenmerkmalen und Leistungsanforderungen.
-
L2 (Euklidan) Entfernung: Verwendet den
<->Operator und berechnet die Quadratwurzel der Summe der Quadratunterschiede. Dies ist die rechenintensivste Option. -
Kosinusabstand: Verwendet den
<=>Operator und misst den Winkel zwischen Vektoren. Es normalisiert die Vektoren intern und erhöht dadurch den Rechenaufwand, bietet aber eine skaleninvariante Ähnlichkeit. -
Inneres Produkt: Verwendet den
<#>-Operator und berechnet das Punktprodukt. Dies ist der schnellste Vorgang, erfordert jedoch pränormale Vektoren für sinnvolle Ähnlichkeitsvergleiche.
Bei Empfehlungsmodulen und semantischer Suche wird der Kosinusabstand häufig bevorzugt, da er Vektoren unterschiedlicher Größenordnungen konsistent behandelt. Wenn Ihre Einbettungen bereits normalisiert sind (viele Einbettungs-APIs geben normalisierte Vektoren zurück), liefert das innere Produkt gleichwertige Ergebnisse mit weniger Berechnung.
Vektorspalten verbrauchen im Vergleich zu herkömmlichen Datentypen einen erheblichen Speicher. Ein einzelner 1536-dimensionaler Vektor, der als float4 (einzelne Genauigkeit) gespeichert ist, erfordert 6.144 Bytes plus Mehraufwand. Eine Tabelle mit einer Million Produkteinbettungen benötigt ca. 6 GB nur für die Vektorspalte. Wenn PostgreSQL Vektorabfragen verarbeitet, werden Vektordaten in den Speicher geladen. Die Beziehung zwischen verfügbarem Arbeitsspeicher und Vektordatengröße wirkt sich direkt darauf aus, ob Abfragen effizient im Arbeitsspeicher ausgeführt werden können oder wiederholt von einem Datenträger gelesen werden müssen.
Höherdimensionale Einbettungen bieten eine größere semantische Auflösung, erhöhen aber sowohl Speicher- als auch Berechnungskosten quadratisch. Ein 3072-dimensionaler Vektor (der von einigen neueren Einbettungsmodellen verwendet wird) erfordert viermal die Entfernungsberechnung und zweimal die Speicherung eines 1536-dimensionalen Vektors. Berücksichtigen Sie beim Auswählen von Einbettungsdimensionen Ihre Genauigkeitsanforderungen. Für viele Empfehlungs- und Suchanwendungen bieten 768 oder 1.024 Dimensionen eine ausreichende Qualität mit sinnvoll geringerem Ressourcenverbrauch.
Speicherkonfiguration für Vektorworkloads
Die Speicherparameter von PostgreSQL wirken sich erheblich auf die Vektorabfrageleistung aus. Durch die ordnungsgemäße Optimierung wird sichergestellt, dass Vektorindizes und häufig verwendete Daten im Arbeitsspeicher verbleiben, wodurch teure Datenträgervorgänge reduziert werden.
Der shared_buffers Parameter steuert den freigegebenen Speichercache von PostgreSQL, in dem sich häufig verwendete Datenseiten befinden. Für Vektor-Workloads sollte dieser Cache groß genug sein, um Ihre Vektorindizes und heiße Daten zu speichern. Ein Cachetrefferverhältnis unter 99% für vektorintensive Arbeitslasten weist darauf hin, dass shared_buffers zu klein sein könnte. In Azure Database for PostgreSQL wird dieser Parameter automatisch basierend auf Ihrer Computeebene abgestimmt, Sie können ihn aber innerhalb des zulässigen Bereichs für Ihre Ebene anpassen. Sorgen Sie dafür, dass Ihre dedizierten Vektorsuchworkloads mit shared_buffers groß genug ausgestattet sind, um Ihre Vektorindizes und einen zusätzlichen Spielraum für andere zwischengespeicherte Daten aufzunehmen. Ein Ausgangspunkt ist 25% des verfügbaren Arbeitsspeichers, der auf der Grundlage der Überwachung zunimmt. Die folgenden Abfragen helfen Ihnen bei der Überprüfung Ihrer aktuellen Einstellungen und der Cacheleistung.
-- Check current setting
SHOW shared_buffers;
-- View buffer cache hit ratio
SELECT
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;
Der work_mem-Parameter steuert den Arbeitsspeicher, der für einzelne Abfragevorgänge wie Sortierungen und Hash-Verknüpfungen verfügbar ist. Vektor-Ähnlichkeitsabfragen, insbesondere solche, die die Vektorsuche mit Filtern und Sortieren kombinieren, profitieren von ausreichenden work_memVorteilen. Der Standardwert work_mem (in der Regel 4 MB) ist häufig zu klein für Vektorvorgänge, die Ergebnisse nach Ähnlichkeit sortieren müssen. Sie können diesen Wert für Sitzungen oder Abfragen erhöhen, die Vektorsuchen mit großen Ergebnismengen durchführen, indem Sie SET work_mem = '256MB'; verwenden. Seien Sie vorsichtig mit Erhöhungen von work_mem, da die Einstellung pro Vorgang pro Verbindung gilt, sodass ein Server, der 100 gleichzeitige Verbindungen mit komplexen Abfragen verarbeitet, im Speicher 100 × work_mem × Operationen pro Abfrage verbrauchen könnte. Bei Vektorworkloads sollten Sie die Einstellung work_mem auf Sitzungsebene für bestimmte Abfragen und nicht global festlegen.
Der effective_cache_size Parameter teilt dem Abfrageplaner mit, wie viel Arbeitsspeicher für die Zwischenspeicherung verfügbar ist, einschließlich der Dateicache von PostgreSQL shared_buffers und des Betriebssystems. Diese Einstellung weist keinen Speicher zu, beeinflusst jedoch, ob der Planer Indexscans über sequenzielle Scans auswählt. Setzen Sie effective_cache_size auf ca. 75 % des gesamten Systemspeichers bei dedizierten Datenbankservern fest. Höhere Werte ermutigen den Planer, Indizes zu verwenden, was in der Regel für die Vektorsuche von Vorteil ist. In Azure Database for PostgreSQL wird dies automatisch basierend auf Ihrer Ebene konfiguriert.
Abfrageplanereinstellungen für die Vektorsuche
Der Abfrageplaner von PostgreSQL trifft Entscheidungen darüber, wie Abfragen basierend auf Kostenschätzungen ausgeführt werden. Mehrere Parameter wirken sich auf diese Schätzungen aus, und die Optimierung für modernen SSD-Speicher verbessert die Vektorabfrageplanung.
Der random_page_cost Parameter schätzt die Kosten für das Lesen einer zufälligen Datenträgerseite relativ zu einer sequenziellen Seite. Der Standardwert von 4,0 spiegelt die Merkmale des sich drehenden Datenträgers wider, bei denen der zufällige Zugriff wesentlich langsamer als der sequenzielle Zugriff ist. Azure Database for PostgreSQL verwendet SSD-Speicher, bei dem zufälliger und sequenzieller Zugriff eine ähnliche Leistung aufweisen. Durch die Senkung von random_page_cost auf 1.1-1.5 wird der Planer ermutigt, Indexscans häufiger zu verwenden, was bei Vektorsuchen von Vorteil ist, die auf verstreute Datenseiten zugreifen. Sie können diese Einstellung mit SET random_page_cost = 1.1;.
Der effective_io_concurrency Parameter teilt PostgreSQL mit, wie viele gleichzeitige Datenträger-E/A-Vorgänge das Speichersystem verarbeiten kann. Höhere Werte ermöglichen es, bei Bitmap-Heap-Scans mehr Seiten parallel vorab zu laden. SSD-Speicher können gleichzeitige E/A-Vorgänge gut verarbeiten. Setzen Sie den Wert von effective_io_concurrency daher für SSD-basierte Azure-Datenbank für PostgreSQL-Instanzen auf 200. Dadurch wird die Leistung für Abfragen verbessert, die die Vektorähnlichkeit mit der Metadatenfilterung kombinieren.
Die Parameter parallel_tuple_cost und parallel_setup_cost steuern, wann PostgreSQL die parallele Abfrageausführung anwendet. Vektorvorgänge können von Parallelität profitieren, insbesondere für sequenzielle Scans in großen Tabellen. Niedrigere Werte für parallel_tuple_cost (Standard 0,1) und parallel_setup_cost (Standard 1000) fördern die parallele Ausführung. Bei Vektorworkloads mit großen Tabellen kann die Aktivierung von Parallelität die Abfragezeit erheblich reduzieren, wenn Indizes nicht verwendet werden. Sie können Ihre aktuellen parallelen Einstellungen mit SHOW parallel_tuple_cost;, SHOW parallel_setup_cost; und SHOW max_parallel_workers_per_gather; überprüfen.
Konfigurieren von pgvectorspezifischen Parametern
Die pgvector-Erweiterung stellt Konfigurationsparameter bereit, die den Kompromiss mit genauigkeitsgeschwindigkeit für indexbasierte Suchvorgänge steuern. Diese Parameter sind für die Optimierung der Vektorabfrageleistung von entscheidender Bedeutung.
Bei Verwendung von IVFFlat-Indizes steuert der ivfflat.probes Parameter, wie viele Indexpartitionen (Listen) für jede Abfrage durchsucht werden. Höhere Werte erhöhen die Erfassungsrate, indem mehr der tatsächlichen nächsten Nachbarn gefunden werden, verlangsamt jedoch Abfragen. Dieser Kompromiss ist für das IVFFlat-Leistungsoptimierung von zentraler Bedeutung. Sie balancieren das Risiko, gute Übereinstimmungen zu verpassen, gegen die Kosten der Suche nach weiteren Partitionen. Der Standardwert von 1 durchsucht nur die einzige vielversprechendste Partition, die schnell ist, aber möglicherweise relevante Ergebnisse verpassen, die in benachbarten Partitionen gespeichert sind. Bei Empfehlungssystemen, bei denen das Verpassen einer guten Übereinstimmung die Benutzererfahrung beeinträchtigt, beginnen Sie mit ivfflat.probes, das auf 5-10 % Ihres lists-Parameters eingestellt ist, und passen Sie es basierend auf der gemessenen Trefferquote an.
-- Configure IVFFlat search depth
SET ivfflat.probes = 10;
-- Execute vector search
SELECT id, name, embedding <=> $1 AS distance
FROM products
ORDER BY embedding <=> $1
LIMIT 10;
Bei HNSW-Indizes steuert der hnsw.ef_search Parameter die Größe der dynamischen Kandidatenliste während der Suche. Größere Werte erkunden mehr vom Graphen und verbessern die Erfassung auf Kosten der Geschwindigkeit. Im Gegensatz zu den diskreten Partitionen von IVFFlat bedeutet die Graphstruktur von HNSW, dass dieser Parameter beeinflusst, wie gründlich der Algorithmus benachbarte Verbindungen untersucht, bevor Ergebnisse zurückgegeben werden. Der Standardwert von 40 bietet eine angemessene Balance für viele Workloads. Erhöhen Sie bei hohen Genauigkeitsanforderungen (wie das Auffinden der tatsächlichen Top-10-Übereinstimmungen) auf 100–200. Bei latenzkritischen Anwendungen, bei denen ungefähre Ergebnisse akzeptabel sind, können Werte bis zu 20 funktionieren. Konfigurieren Sie hnsw.ef_search mit SET hnsw.ef_search = 100;, bevor Sie Ihre Vektorsuche ausführen. Der optimale Wert hängt von Ihren Genauigkeitsanforderungen und dem Latenzbudget ab. Benchmark mit repräsentativen Abfragen, um die optimale Balance für Ihre Anwendung zu finden.
Überwachen und Messen der Leistung
Optimierung ohne Messung ist Schätzarbeit. Verwenden Sie die integrierten Tools von PostgreSQL und Azure Monitor, um das Abfrageverhalten zu verstehen und Konfigurationsänderungen zu überprüfen.
Der EXPLAIN ANALYZE Befehl zeigt, wie PostgreSQL eine Abfrage ausführt und liefert tatsächliche Zeitinformationen. Bei Vektorabfragen zeigt dies an, ob Indizes verwendet werden und wo Zeit aufgewendet wird. Wenn Sie den Ausführungsplan verstehen, können Sie ermitteln, ob schlechte Leistung aus fehlenden Indizes, suboptimalen Parametereinstellungen oder Datenverteilungsproblemen resultiert. Führen Sie EXPLAIN ANALYZE vor der Vektorabfrage aus, um den Ausführungsplan anzuzeigen. Suchen Sie mithilfe von [index_name] nach Indexscan (gibt an, dass der Vektorindex verwendet wird), seq Scan (gibt einen sequenziellen Scan an, der für große Tabellen langsam ist), tatsächliche Zeitwerte (zeigen Sie an, wo die Ausführungszeit aufgewendet wird) und Zeilenanzahl (helfen, festzustellen, ob die Filterung effizient funktioniert). Wenn sequenzielle Scans angezeigt werden und Sie die Nutzung von Indizes erwarten, überprüfen Sie, ob der Distanzoperator der Abfrage zur Operatorklasse des Indexes passt (zum Beispiel unter Verwendung von <=> mit einem Index, der mit vector_cosine_ops erstellt wurde).
Manchmal wählt PostgreSQL aus, keinen verfügbaren Index zu verwenden. Häufige Gründe für Vektorabfragen sind Abfragen, die einen großen Teil der Tabelle zurückgeben (Indexaufwand überschreitet sequenzielle Überprüfung), veraltete Statistiken nach signifikanten Datenänderungen oder einen Entfernungsoperator, der nicht mit der Operatorklasse des Indexes übereinstimmt. Führen Sie ANALYZE products; aus, um die Statistiken für eine genaue Planung zu aktualisieren. Sie können Indexinformationen mit SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'products'; prüfen.
Azure Database for PostgreSQL macht Metriken über Azure Monitor verfügbar, die helfen, Leistungsengpässe zu identifizieren. Überwachen Sie CPU-Prozent (anhaltend hohe CPU-Auslastung weist auf rechenintensive Vektoroperationen hin), Arbeitsspeicherprozent (nähernde Grenzwerte deuten darauf hin, dass die Berechnungsstufe erhöht oder Abfragen optimiert werden sollten), Speicher-E/A-Prozent (hohe Werte deuten darauf hin, dass Daten nicht in den Cache passen), und aktive Verbindungen (annähernde Grenzwerte deuten darauf hin, dass Verbindungspooling hilfreich sein könnte). Richten Sie Warnungen für diese Metriken ein, um Leistungsbeeinträchtigungen abzufangen, bevor sie sich auf Benutzer auswirkt.
Bewährte Methoden zur Optimierung von Pgvector
Effektive Optimierung folgt einem systematischen Ansatz und nicht zufälligen Parameteränderungen.
- Zuerst Baselines festlegen: Vor Änderungen die Abfragelatenz und die Ressourcennutzung messen. Ohne Basispläne können Sie nicht ermitteln, ob Änderungen helfen oder verletzen.
- Ändern Sie jeweils einen Parameter: Mehrere gleichzeitige Änderungen machen es unmöglich, Verbesserungen oder Regressionen bestimmten Einstellungen zuzuordnen.
- Testen mit produktionsähnlichen Daten: Die Abfrageleistung variiert erheblich mit der Datengröße und -verteilung. Die Optimierung auf kleinen Testdatensätzen erzeugt häufig Einstellungen, die im größeren Maßstab scheitern.
- Überwachen auf Regressionen: Parameter, die die Vektorsuche verbessern, wirken sich möglicherweise negativ auf andere Workloads aus. Überwachen Sie den allgemeinen Systemzustand nach Änderungen.
- Dokumentieren Sie Ihre Einstellungen: Notieren Sie sich, was Sie geändert haben, warum und welche Wirkung sie hatte. Diese Dokumentation ist bei der Problembehandlung zukünftiger Probleme unschätzbar.