In diesem Dokument werden Best Practices zum Optimieren der Leistung von Spanner Graph-Abfragen beschrieben, darunter die folgenden Optimierungen:
- Vermeiden Sie einen vollständigen Scan der Eingabetabelle für Knoten und Kanten.
- Reduzieren Sie die Datenmenge, die die Abfrage aus dem Speicher lesen muss.
- Größe der Zwischendaten reduzieren
Mit Knoten mit niedriger Kardinalität beginnen
Schreiben Sie den Pfad so, dass er mit den Knoten mit niedriger Kardinalität beginnt. So bleibt die Zwischenergebnismenge klein und die Abfrageausführung wird beschleunigt.
Die folgenden Abfragen haben beispielsweise dieselbe Semantik:
Vorwärtskanten-Traversal:
GRAPH FinGraph MATCH (p:Person {name:"Alex"})-[:Owns]->(a:Account {is_blocked: true}) RETURN p.id AS person_id, a.id AS account_id;Rückwärts durch Kanten gehen:
GRAPH FinGraph MATCH (a:Account {is_blocked:true})<-[:Owns]-(p:Person {name: "Alex"}) RETURN p.id AS person_id, a.id AS account_id;
Angenommen, es gibt weniger Personen mit dem Namen Alex als blockierte Konten. In diesem Fall empfehlen wir, diese Abfrage im Forward-Edge-Traversal zu schreiben.
Das Starten mit Knoten mit niedrigerer Kardinalität ist besonders wichtig für die Pfadsuche mit variabler Länge. Im folgenden Beispiel wird die empfohlene Methode zum Suchen von Konten gezeigt, die sich innerhalb von drei Übertragungen eines bestimmten Kontos befinden.
GRAPH FinGraph
MATCH (:Account {id: 7})-[:Transfers]->{1,3}(a:Account)
RETURN a.id;
Alle Labels standardmäßig angeben
Spanner Graph leitet die infrage kommenden Knoten und Kantenlabels ab, wenn Labels weggelassen werden. Wir empfehlen, nach Möglichkeit Labels für alle Knoten und Kanten anzugeben, da diese Ableitung nicht immer möglich ist und möglicherweise mehr Labels als nötig gescannt werden.
Einzelne MATCH-Anweisung
Im folgenden Beispiel werden Konten gesucht, die durch maximal drei Übertragungen mit dem angegebenen Konto verknüpft sind:
GRAPH FinGraph
MATCH (src:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id;
Über MATCH-Anweisungen hinweg
Geben Sie Labels für Knoten und Kanten an, wenn sie sich auf dasselbe Element beziehen, aber über MATCH-Anweisungen hinweg verwendet werden.
Das folgende Beispiel veranschaulicht diesen empfohlenen Ansatz:
GRAPH FinGraph
MATCH (acct:Account {id: 7})-[:Transfers]->{1,3}(other_acct:Account)
RETURN acct, COUNT(DISTINCT other_acct) AS related_accts
GROUP BY acct
NEXT
MATCH (acct:Account)<-[:Owns]-(p:Person)
RETURN p.id AS person, acct.id AS acct, related_accts;
IS_FIRST zum Optimieren von Abfragen verwenden
Mit der Funktion IS_FIRST können Sie die Abfrageleistung verbessern, indem Sie Kanten stichprobenartig erfassen und Traversierungen in Diagrammen einschränken. Diese Funktion hilft, Knoten mit hoher Kardinalität zu verarbeiten und Multi-Hop-Abfragen zu optimieren.
Wenn die angegebene Stichprobengröße zu klein ist, werden bei der Abfrage möglicherweise keine Daten zurückgegeben. Daher müssen Sie möglicherweise verschiedene Stichprobengrößen ausprobieren, um das optimale Gleichgewicht zwischen zurückgegebenen Daten und verbesserter Abfrageleistung zu finden.
In diesen IS_FIRST-Beispielen wird FinGraph verwendet, ein Finanzdiagramm mit Account Knoten und Transfers Kanten für Geldüberweisungen. Informationen zum Erstellen der FinGraph und zum Ausführen der Beispielabfragen damit finden Sie unter Cloud Spanner Graph einrichten und abfragen.
Durchlaufene Kanten begrenzen, um die Abfrageleistung zu verbessern
Wenn Sie Diagramme abfragen, kann die Anzahl der eingehenden oder ausgehenden Kanten für einige Knoten deutlich höher sein als für andere. Diese Knoten mit hoher Kardinalität werden manchmal als Superknoten oder Hub-Knoten bezeichnet. Superknoten können Leistungsprobleme verursachen, da bei Traversierungen durch sie möglicherweise riesige Datenmengen verarbeitet werden müssen, was zu Datenabweichungen und langen Ausführungszeiten führt.
Um eine Abfrage eines Graphen mit Superknoten zu optimieren, verwenden Sie die Funktion IS_FIRST in einer FILTER-Klausel, um die Anzahl der Kanten zu begrenzen, die die Abfrage von einem Knoten aus durchläuft. Da Konten in FinGraph möglicherweise deutlich mehr Transaktionen als andere haben, können Sie IS_FIRST verwenden, um eine ineffiziente Abfrage zu verhindern. Diese Technik ist besonders nützlich, wenn Sie keine vollständige Aufzählung aller Verbindungen von einem Superknoten benötigen.
Mit der folgenden Abfrage werden Konten (a2) ermittelt, die direkt oder indirekt Überweisungen von gesperrten Konten (a1) erhalten. In der Abfrage wird IS_FIRST verwendet, um die Leistung zu verbessern, wenn ein Konto viele Überweisungen hat. Dazu wird die Anzahl der Transfers-Kanten begrenzt, die für jedes Account berücksichtigt werden.
GRAPH FinGraph
MATCH
(a1:Account {is_blocked: true})
-[e:Transfers WHERE e IN
{
MATCH -[selected_e:Transfers]->
FILTER IS_FIRST(@max_transfers_per_account) OVER (
PARTITION BY SOURCE_NODE_ID(selected_e)
ORDER BY selected_e.create_time DESC)
RETURN selected_e
}
]->{1,5}
(a2:Account)
RETURN a1.id AS src_id, a2.id AS dst_id;
In diesem Beispiel wird Folgendes verwendet:
@max_transfers_per_account: Ein Abfrageparameter, der die maximale Anzahl vonTransfers-Kanten angibt, die für jedes Konto (a1) berücksichtigt werden sollen.PARTITION BY SOURCE_NODE_ID(selected_e): Sorgt dafür, dass dasIS_FIRST-Limit unabhängig für jedes Konto (a1) gilt.ORDER BY selected_e.create_time DESC: Gibt an, dass die letzten Übertragungen zurückgegeben werden.
Zwischenknoten für die Optimierung von Multi-Hop-Abfragen auswählen
Sie können die Abfrageeffizienz auch verbessern, indem Sie IS_FIRST verwenden, um Zwischenknoten in Multi-Hop-Abfragen zu erfassen. Diese Technik verbessert die Effizienz, indem die Anzahl der Pfade begrenzt wird, die bei jeder Zwischenstufe der Abfrage berücksichtigt werden. Dazu müssen Sie eine Multi-Hop-Abfrage in mehrere MATCH-Anweisungen aufteilen, die durch NEXT getrennt sind, und IS_FIRST in der Mitte anwenden, an der Sie Stichproben nehmen müssen:
GRAPH FinGraph
MATCH (a1:Account {is_blocked: true})-[e1:Transfers]->(a2:Account)
FILTER IS_FIRST(1) OVER (PARTITION BY a2)
RETURN a1, a2
NEXT
MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;
So optimiert IS_FIRST diese Abfrage:
Die Klausel
FILTER IS_FIRST(1) OVER (PARTITION BY a2)wird in der erstenMATCH-Anweisung angewendet.Für jeden Zwischenkontoknoten (
a2) wird inIS_FIRSTnur die erste eingehendeTransfers-Kante (e1) berücksichtigt. Dadurch wird die Anzahl der Pfade, die in der zweitenMATCH-Anweisung untersucht werden müssen, reduziert.Die Effizienz der gesamten Two-Hop-Abfrage wird verbessert, da die zweite
MATCHkeine unnötigen Daten verarbeitet, insbesondere wenna2viele eingehende Transfers hat.