Leistung von Vektorabfragen optimieren

Wählen Sie eine Dokumentationsversion aus:

In diesem Dokument wird beschrieben, wie Sie Ihre Indexe optimieren, um eine schnellere Abfrageleistung und einen besseren Recall zu erzielen.

ScaNN-Index optimieren

Der ScaNN-Index verwendet eine baumbasierte Quantisierung. Bei der Baumquantisierung wird ein Suchbaum zusammen mit einer Quantisierungs- oder Hash-Funktion gelernt. Wenn Sie eine Abfrage ausführen, wird der Suchbaum verwendet, um den Suchraum zu verkleinern, während die Quantisierung zur Komprimierung der Indexgröße dient. Durch diese Bereinigung wird die Berechnung der Ähnlichkeit (d.h. des Abstands) zwischen dem Anfragevektor und den Datenbankvektoren beschleunigt.

Um sowohl eine hohe QPS-Rate (Queries per Second, Abfragen pro Sekunde) als auch einen hohen Recall bei Ihren Nearest-Neighbor-Abfragen zu erzielen, müssen Sie den Baum Ihres ScaNN-Index so partitionieren, dass er am besten zu Ihren Daten und Abfragen passt.

Bevor Sie einen ScaNN-Index erstellen, müssen Sie Folgendes tun:

  • Prüfen Sie, ob bereits eine Tabelle mit Ihren Daten erstellt wurde.
  • Achten Sie darauf, dass der Wert, den Sie für das Flag maintenance_work_mem und shared_buffers festlegen, kleiner als der Gesamtspeicher der Maschine ist, um Probleme beim Generieren des Index zu vermeiden.

Parameter für die Abstimmung

Die folgenden Indexparameter und Datenbank-Flags werden zusammen verwendet, um das richtige Gleichgewicht zwischen Recall und QPS zu finden. Alle Parameter gelten für beide ScaNN-Indextypen.

Abstimmungsparameter Beschreibung Parametertyp
num_leaves Die Anzahl der Partitionen, die auf diesen Index angewendet werden sollen. Die Anzahl der Partitionen, die Sie beim Erstellen eines Index anwenden, wirkt sich auf die Indexleistung aus. Wenn Sie die Anzahl der Partitionen für eine bestimmte Anzahl von Vektoren erhöhen, erstellen Sie einen detaillierteren Index, der den Recall und die Abfrageleistung verbessert. Dies führt jedoch zu längeren Indexerstellungszeiten.

Da dreistufige Bäume schneller erstellt werden als zweistufige Bäume, können Sie den Wert von num_leaves_value beim Erstellen eines dreistufigen Baumindex erhöhen, um eine bessere Leistung zu erzielen.
  • Index auf zwei Ebenen: Legen Sie diesen Wert auf einen beliebigen Wert zwischen 1 und 1048576 fest.

    Wenn Sie sich nicht sicher sind, welchen Wert Sie auswählen sollen, verwenden Sie sqrt(ROWS) als Ausgangspunkt, wobei ROWS die Anzahl der Vektorzeilen ist. Die Anzahl der Vektoren in jeder Partition wird mit
    ROWS/sqrt(ROWS) = sqrt(ROWS).

    berechnet. Da ein Index mit zweistufigem Baum für ein Dataset mit weniger als 10 Millionen Vektorzeilen erstellt werden kann, enthält jede Partition weniger als (sqrt(10M)) Vektoren, also 3200 Vektoren. Für eine optimale Leistung wird empfohlen, die Anzahl der Vektoren in jeder Partition zu minimieren.
  • Index mit drei Ebenen: Legen Sie diesen Wert auf einen beliebigen Wert zwischen 1 und 1048576 fest.

    Wenn Sie sich nicht sicher sind, welchen Wert Sie auswählen sollen, verwenden Sie power(ROWS, 2/3) als Ausgangspunkt, wobei ROWS die Anzahl der Vektorzeilen ist. Die Anzahl der Vektoren in jeder Partition wird mit
    ROWS/power(ROWS, 2/3) = power(ROWS, 1/3).

    berechnet. Da ein Index mit dreistufiger Baumstruktur für ein Dataset mit mehr als 100 Millionen Vektorzeilen erstellt werden kann, enthält jede Partition mehr als
    (power(100M, 1/3)) Vektoren, also 465 Vektoren. Für eine optimale Leistung wird empfohlen, die Anzahl der Vektoren in jeder Partition zu minimieren.
Index erstellen
quantizer Der Typ des Quantizers, den Sie für den K-Means-Baum verwenden möchten. Der Standardwert ist SQ8, um die Abfrageleistung zu verbessern.

Legen Sie ihn auf FLAT fest, um den Recall zu verbessern.
Index erstellen
enable_pca Aktiviert die Hauptkomponentenanalyse (Principal Component Analysis, PCA). Das ist eine Technik zur Dimensionsreduzierung, mit der die Größe des Einbettungsvektors automatisch reduziert wird, wenn möglich. Diese Option ist standardmäßig aktiviert.

Setzen Sie sie auf false, wenn Sie eine Verschlechterung des Erinnerungsvermögens feststellen.
Index erstellen
scann.num_leaves_to_search Das Datenbank-Flag steuert den Kompromiss zwischen Trefferquote und QPS. Der Standardwert ist 1% des in num_leaves festgelegten Werts.

Je höher der festgelegte Wert, desto besser ist der Recall, aber desto niedriger ist die QPS. Das gilt auch umgekehrt.
Laufzeit der Abfrage
scann.max_top_neighbors_buffer_size Das Datenbankflag gibt die Größe des Cache an, der verwendet wird, um die Leistung für gefilterte Abfragen zu verbessern. Dazu werden die gescannten Kandidatennachbarn im Arbeitsspeicher anstelle auf der Festplatte bewertet oder eingestuft. Der Standardwert ist 20000.

 Je höher der festgelegte Wert, desto besser ist die QPS bei gefilterten Abfragen. Dies führt jedoch zu einer höheren Arbeitsspeichernutzung und umgekehrt.
Laufzeit der Abfrage
scann.pre_reordering_num_neighbors Das Datenbankflag gibt an, wie viele Kandidatennachbarn in den Neusortierungsphasen berücksichtigt werden sollen, nachdem bei der ersten Suche eine Reihe von Kandidaten ermittelt wurde. Legen Sie hier einen Wert fest, der höher ist als die Anzahl der Nachbarn, die von der Abfrage zurückgegeben werden sollen.

Höhere Werte führen zu einem besseren Recall, aber auch zu einer geringeren Anzahl von Anfragen pro Sekunde.
Laufzeit der Abfrage
max_num_levels Die maximale Anzahl von Ebenen des K-Means-Clustering-Baums.
  • Zweistufiger Baumindex: Standardeinstellung für die zweistufige baumbasierte Quantisierung.
  • Baumindex mit drei Ebenen: Wird für die baumbasierte Quantisierung mit drei Ebenen explizit auf 2 festgelegt.
Index erstellen

ScaNN-Index optimieren

Sehen Sie sich die folgenden Beispiele für ScaNN-Indexe mit zwei und drei Ebenen an, um zu sehen, wie die Optimierungsparameter festgelegt werden:

Index mit zwei Ebenen

SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 1/2)]);

Index mit drei Ebenen

SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);

Jeder Einfüge- oder Aktualisierungsvorgang für eine Tabelle, für die bereits ein ScaNN-Index generiert wurde, wirkt sich darauf aus, wie der gelernte Baum den Index optimiert. Wenn Ihre Tabelle häufig aktualisiert oder neue Zeilen eingefügt werden, empfehlen wir, den vorhandenen ScaNN-Index regelmäßig neu zu indexieren, um die Genauigkeit des Rückrufs zu verbessern.

Sie können Indexmesswerte überwachen, um die Anzahl der Änderungen zu ermitteln, die seit der Erstellung des Index vorgenommen wurden, und den Index entsprechend neu indexieren. Weitere Informationen zu Messwerten finden Sie unter Messwerte für Vektorindex.

Best Practices für die Optimierung

Je nach Art des ScaNN-Index, den Sie verwenden möchten, variieren die Empfehlungen zum Optimieren des Index. In diesem Abschnitt finden Sie Empfehlungen zum Optimieren von Indexparametern, um ein optimales Gleichgewicht zwischen Recall und QPS zu erreichen.

Zweistufiger Baumindex

So wenden Sie Empfehlungen an, um die optimalen Werte für num_leaves und num_leaves_to_search für Ihren Datensatz zu ermitteln:

  1. Erstellen Sie den Index ScaNN mit num_leaves, das auf die Quadratwurzel der Zeilenanzahl der indexierten Tabelle festgelegt ist.
  2. Führen Sie Ihre Testabfragen aus und erhöhen Sie den Wert von scann.num_of_leaves_to_search, bis Sie den gewünschten Recall-Bereich erreichen, z. B. 95%. Weitere Informationen zum Analysieren von Abfragen finden Sie unter Abfragen analysieren.
  3. Notieren Sie sich das Verhältnis zwischen scann.num_leaves_to_search und num_leaves, das in den nachfolgenden Schritten verwendet wird. Dieses Verhältnis bietet eine Annäherung an den Datensatz, mit dem Sie den angestrebten Recall erreichen können.

    Wenn Sie mit Vektoren mit hoher Dimensionalität (500 Dimensionen oder mehr) arbeiten und den Recall verbessern möchten, versuchen Sie, den Wert von scann.pre_reordering_num_neighbors zu optimieren. Legen Sie den Wert als Ausgangspunkt auf 100 * sqrt(K) fest, wobei K das Limit ist, das Sie in Ihrer Abfrage festgelegt haben.
  4. Wenn Ihre Rate von Abfragen pro Sekunde zu niedrig ist, nachdem Ihre Anfragen ein bestimmtes Ziel für den Recall erreicht haben, gehen Sie so vor:
    1. Erstellen Sie den Index neu und erhöhen Sie den Wert von num_leaves und scann.num_leaves_to_search gemäß der folgenden Anleitung:
      • Setzen Sie num_leaves auf einen größeren Faktor der Quadratwurzel der Anzahl der Zeilen. Wenn der Index beispielsweise num_leaves auf die Quadratwurzel der Zeilenanzahl festgelegt hat, versuchen Sie, ihn auf das Doppelte der Quadratwurzel festzulegen. Wenn der Wert bereits verdoppelt wurde, versuchen Sie, ihn auf das Dreifache der Quadratwurzel zu setzen.
      • Erhöhen Sie scann.num_leaves_to_search nach Bedarf, um das Verhältnis zu num_leaves beizubehalten, das Sie in Schritt 3 notiert haben.
      • Legen Sie für num_leaves einen Wert fest, der kleiner oder gleich der Zeilenanzahl geteilt durch 100 ist.
    2. Führen Sie die Testabfragen noch einmal aus. Während Sie die Testanfragen ausführen, können Sie mit einer Reduzierung von scann.num_leaves_to_search experimentieren, um einen Wert zu finden, der die Anzahl der Abfragen pro Sekunde erhöht und gleichzeitig die Trefferquote hoch hält. Sie können verschiedene Werte für scann.num_leaves_to_search ausprobieren, ohne den Index neu erstellen zu müssen.
  5. Wiederholen Sie Schritt 4, bis sowohl die QPS als auch der Recall-Bereich akzeptable Werte erreicht haben.

Baumindex mit drei Ebenen

Zusätzlich zu den Empfehlungen für den ScaNN-Index mit zwei Ebenen sollten Sie die folgenden Richtlinien und Schritte zur Optimierung des Index verwenden:

  • Wenn Sie die max_num_levels für einen Baum mit zwei Ebenen von 1 auf 2 für einen Baum mit drei Ebenen erhöhen, verkürzt sich die Zeit zum Erstellen eines Index erheblich, allerdings auf Kosten der Recall-Genauigkeit. Legen Sie max_num_levels anhand der folgenden Empfehlung fest:
    • Legen Sie den Wert auf 2 fest, wenn die Anzahl der Vektorzeilen 100 Millionen überschreitet.
    • Legen Sie den Wert auf 1 fest, wenn die Anzahl der Vektorzeilen weniger als 10 Millionen beträgt.
    • Legen Sie den Wert auf 1 oder 2 fest, wenn die Anzahl der Vektorzeilen zwischen 10 Millionen und 100 Millionen liegt. Die Entscheidung hängt davon ab, wie wichtig Ihnen die Indexerstellungszeit und die Recall-Genauigkeit sind.

So wenden Sie Empfehlungen an, um den optimalen Wert der Indexparameter num_leaves und max_num_levels zu ermitteln:

  1. Erstellen Sie den ScaNN-Index mit den folgenden num_leaves- und max_num_levels-Kombinationen basierend auf Ihrem Dataset:

    • Vektorzeilen mit mehr als 100 Millionen Zeilen: Legen Sie max_num_levels als 2 und num_leaves als power(rows, ⅔) fest.
    • Vektorzeilen mit weniger als 100 Millionen Zeilen: Legen Sie max_num_levels als 1 und num_leaves als sqrt(rows) fest.
    • Vektorzeilen zwischen 10 Millionen und 100 Millionen Zeilen: Legen Sie zuerst max_num_levels als 1 und num_leaves als sqrt(rows) fest.
  2. Führen Sie Ihre Testabfragen aus. Weitere Informationen zum Analysieren von Abfragen finden Sie unter Abfragen analysieren.

    Wenn die Indexerstellungszeit zufriedenstellend ist, behalten Sie den max_num_levels-Wert bei und testen Sie den num_leaves-Wert, um die optimale Genauigkeit des Rückrufs zu ermitteln.

  3. Wenn Sie mit der Indexierungszeit nicht zufrieden sind, gehen Sie so vor:

    • Wenn der Wert von max_num_levels 1 ist, wird der Index gelöscht. Erstellen Sie den Index neu und legen Sie den Wert max_num_levels auf 2 fest.

      Führen Sie die Abfragen aus und passen Sie den num_leaves-Wert an, um eine optimale Trefferquoten-Genauigkeit zu erzielen.

    • Wenn der Wert von max_num_levels 2 ist, wird der Index gelöscht. Erstellen Sie den Index mit demselben max_num_levels-Wert neu und optimieren Sie den num_leaves-Wert für eine optimale Genauigkeit des Rückrufs.

IVF-Index optimieren

Durch Anpassen der Werte, die Sie für die Parameter lists, ivf.probes und quantizer festlegen, lässt sich die Leistung Ihrer Anwendung möglicherweise optimieren:

Abstimmungsparameter Beschreibung Parametertyp
lists Die Anzahl der Listen, die beim Erstellen des Index erstellt wurden. Der Ausgangspunkt für die Festlegung dieses Werts ist (rows)/1000 für bis zu einer Million Zeilen und sqrt(rows) für mehr als eine Million Zeilen. Index erstellen
quantizer Der Typ des Quantizers, den Sie für den K-Means-Baum verwenden möchten. Der Standardwert ist SQ8, um die Abfrageleistung zu verbessern. Stelle sie auf FLAT ein, um die Erinnerung zu verbessern. Index erstellen
ivf.probes Die Anzahl der nächsten Listen, die bei der Suche untersucht werden sollen. Der Ausgangspunkt für diesen Wert ist
sqrt(lists).
Laufzeit der Abfrage

Im folgenden Beispiel sehen Sie einen IVF-Index mit den festgelegten Optimierungsparametern:

SET LOCAL ivf.probes = 10;

CREATE INDEX my-ivf-index ON my-table
  USING ivf (vector_column cosine)
  WITH (lists = 100, quantizer = 'SQ8');

IVFFlat-Index optimieren

Durch Anpassen der Werte, die Sie für die Parameter lists und ivfflat.probes festlegen, können Sie die Anwendungsleistung optimieren:

Abstimmungsparameter Beschreibung Parametertyp
lists Die Anzahl der Listen, die beim Erstellen des Index erstellt wurden. Der Ausgangspunkt für die Festlegung dieses Werts ist (rows)/1000 für bis zu einer Million Zeilen und sqrt(rows) für mehr als eine Million Zeilen. Index erstellen
ivfflat.probes Die Anzahl der Listen mit den nächsten Nachbarn, die bei der Suche untersucht werden sollen. Der Ausgangspunkt für diesen Wert ist
sqrt(lists).
Laufzeit der Abfrage

Bevor Sie einen IVFFlat-Index erstellen, muss das max_parallel_maintenance_workers-Flag Ihrer Datenbank auf einen Wert gesetzt sein, der ausreicht, um die Indexerstellung für große Tabellen zu beschleunigen.

Im folgenden Beispiel sehen Sie einen IVFFlat-Index mit den festgelegten Optimierungsparametern:

SET LOCAL ivfflat.probes = 10;

CREATE INDEX my-ivfflat-index ON my-table
  USING ivfflat (vector_column cosine)
  WITH (lists = 100);

HNSW-Index optimieren

Durch Anpassen der Werte, die Sie für die Parameter m, ef_construction und hnsw.ef_search festlegen, lässt sich die Anwendungsleistung optimieren.

Abstimmungsparameter Beschreibung Parametertyp
m Die maximale Anzahl von Verbindungen pro Knoten im Diagramm. Sie können mit dem Standardwert 16(default) beginnen und je nach Größe Ihres Datasets höhere Werte ausprobieren. Index erstellen
ef_construction Die Größe der dynamischen Kandidatenliste, die während der Erstellung des Diagramms verwaltet wird. Sie wird ständig aktualisiert und enthält die aktuell besten Kandidaten für die nächsten Nachbarn eines Knotens. Legen Sie für diesen Wert einen beliebigen Wert fest, der höher als das Doppelte des m-Werts ist, z. B. 64(Standard). Index erstellen
ef_search Die Größe der dynamischen Kandidatenliste, die bei der Suche verwendet wird. Sie können diesen Wert zuerst auf m oder ef_construction festlegen und ihn dann ändern, während Sie den Recall beobachten. Der Standardwert ist 40. Laufzeit der Abfrage

Im folgenden Beispiel sehen Sie einen hnsw-Index mit den festgelegten Optimierungsparametern:

SET LOCAL hnsw.ef_search = 40;

CREATE INDEX my-hnsw-index ON my-table
  USING hnsw (vector_column cosine)
  WITH (m = 16, ef_construction = 200);

Abfragen analysieren

Verwenden Sie den Befehl EXPLAIN ANALYZE, um Ihre Abfragestatistiken zu analysieren, wie in der folgenden SQL-Beispielabfrage gezeigt.

  EXPLAIN ANALYZE SELECT result-column FROM my-table
    ORDER BY EMBEDDING_COLUMN ::vector
    USING INDEX my-scann-index
    <-> embedding('textembedding-gecko@003', 'What is a database?')
    LIMIT 1;

Die Beispielantwort QUERY PLAN enthält Informationen wie die benötigte Zeit, die Anzahl der gescannten oder zurückgegebenen Zeilen und die verwendeten Ressourcen.

Limit  (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
  ->  Index Scan using my-scann-index on my-table  (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
        Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
        Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms

Messwerte für Vektorindexe ansehen

Mithilfe der Messwerte für Vektorindexe können Sie die Leistung Ihres Vektorindex überprüfen, Bereiche für Verbesserungen identifizieren und den Index bei Bedarf anhand der Messwerte optimieren.

Wenn Sie alle Messwerte für Vektorindexe aufrufen möchten, führen Sie die folgende SQL-Abfrage aus, in der die Ansicht pg_stat_ann_indexes verwendet wird:

SELECT * FROM pg_stat_ann_indexes;

Weitere Informationen zur vollständigen Liste der Messwerte finden Sie unter Messwerte für Vektorindex.

Nächste Schritte