Best Practices für Graphabfragen
In diesem Dokument werden Best Practices zur Optimierung Ihrer BigQuery-Graphabfragen beschrieben.
Pfadtraversierung von Knoten mit niedriger Kardinalität starten
Damit Zwischenergebnismengen klein bleiben und die Abfrageausführung beschleunigt wird, sollten Sie Ihre Graphabfragen so schreiben, dass die Pfadtraversierung von Knoten mit niedrigerer Kardinalität aus startet, unabhängig von der Richtung der Pfadtraversierung. In den folgenden MATCH-Anweisungen werden Eigenschaftsfilter verwendet, um die Anzahl der möglichen Startknoten zu reduzieren, anstatt alle Übereinstimmungen zu berechnen und dann zu filtern:
MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)
MATCH (a:Account WHERE balance > 10)<-[own:Owns]-(p:Person)
Dies ist besonders wichtig für quantifizierte Pfadabfragen:
MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)
`ANY`- oder `ANY SHORTEST`-Syntax für Konnektivitätsprüfungen verwenden
Quantifizierte Pfadabfragen können doppelte Pfade zwischen Quell- und Zielknoten zurückgeben. Wenn Sie die Konnektivität prüfen möchten und nicht
alle möglichen Pfade benötigen, verwenden Sie ANY oder ANY SHORTEST, um redundante
Berechnungen zu reduzieren und die Effizienz der Pfadsuche zu verbessern. In der folgenden MATCH-Anweisung wird beispielsweise ANY SHORTEST verwendet, um nur einen Pfad zwischen jedem Knotenpaar beizubehalten:
MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)
Direktionale Pfadtraversierung verwenden
BigQuery-Graphschemata sind direktional. Das bedeutet, dass jede Kante einen Quell- und einen Zielknoten hat. Obwohl die Graphabfragesyntax die Pfadtraversierung in jeder Richtung zulässt (z. B. -[edge]-), empfehlen wir die Verwendung der direktionalen Pfadtraversierung (z. B. -[edge]-> oder
<-[edge]-) für eine bessere Leistung. Die Pfadtraversierung in beliebiger Richtung kann zu Leistungseinbußen führen.
In der folgenden MATCH-Anweisung wird die Pfadtraversierung in beliebiger Richtung verwendet:
-- Avoid.
MATCH (a1:Account {id: 7})-[t:Transfers]-(a2:Account)
Kombinieren Sie stattdessen zwei direktionale Traversierungen mit UNION ALL:
MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account {id: 7})<-[t:Transfers]-(a2:Account)
Labels explizit angeben
Wenn in einer Abfrage Knoten- oder Kantenlabels ausgelassen werden, zählt BigQuery Graph alle infrage kommenden Knoten- und Kantenlabels auf. Bei dieser Aufzählung werden möglicherweise mehr Labels gescannt als nötig. Geben Sie daher nach Möglichkeit Labels für alle Knoten und Kanten in Ihrer Abfrage an.
In der folgenden Abfrage werden beispielsweise die Labels Account und Transfers angegeben:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;
Vermeiden Sie es, Labels auszulassen, da sonst möglicherweise andere unnötige Beziehungen zwischen Knoten gescannt werden. In der folgenden Abfrage kann a1 ein Konto oder eine
Person darstellen und t kann für eine Überweisung oder ein Konto stehen.
GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;
Eine einzelne MATCH-Anweisung bevorzugen
Mit BigQuery Graph können Sie mehrere MATCH-Anweisungen in eine einzelne Graphabfrage einfügen. Diese Anweisungen sind durch mehrfach deklarierte Variablen verbunden, die denselben Knoten oder dieselbe Kante darstellen. Die Verwendung mehrerer MATCH-Anweisungen kann jedoch die Vorteile der Kardinalität über Anweisungen hinweg verringern. Verwenden Sie nach Möglichkeit eine einzelne MATCH-Anweisung, um die Leistung zu verbessern.
Die folgenden Abfragen sind beispielsweise gleichwertig, aber die erste ist leistungsstärker, da sie eine einzelne MATCH-Anweisung verwendet:
-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
(p:Person {id: 1})-[o:Owns]->
(a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
Traversierte Kanten von Knoten mit hoher Kardinalität begrenzen
Beim Abfragen von Graphen kann die Anzahl der eingehenden oder ausgehenden Kanten einiger Knoten deutlich höher sein als bei anderen Knoten. Diese Knoten mit hoher Kardinalität werden manchmal als Superknoten oder Hubknoten bezeichnet. Superknoten können Leistungsprobleme verursachen, da bei der Traversierung durch sie große Datenmengen verarbeitet werden müssen, was zu einer ungleichmäßigen Datenverteilung und langen Ausführungszeiten führt.
Um eine Abfrage eines Graphen mit Superknoten zu optimieren, verwenden Sie die
ROW_NUMBER() Funktion
in einer FILTER- oder WHERE-Klausel in MATCH, um die
Anzahl der Kanten zu begrenzen, die die Abfrage von oder zu einem Knoten traversiert. Diese Methode ist besonders nützlich, wenn Sie keine vollständige Aufzählung aller Verbindungen von oder zu einem Superknoten benötigen.
Wenn beispielsweise einige Konten in FinGraph eine große Anzahl von Transaktionen haben, können Sie mit ROW_NUMBER() die Anzahl der Transfers-Kanten begrenzen, die für jedes Account berücksichtigt werden sollen, und so eine ineffiziente Abfrage vermeiden:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
GRAPH graph_db.FinGraph
-- Sample 5 edges per source node
MATCH -[selected_e:Transfers]->
FILTER ROW_NUMBER() OVER (
PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;
Zwischenknoten oder ‑kanten in Abfragen mit mehreren Schritten abtasten
Sie können die Abfrageeffizienz auch verbessern, indem Sie ROW_NUMBER() verwenden, um Zwischenknoten in Abfragen mit mehreren Schritten abzutasten. Diese Methode verbessert die Effizienz, indem sie die Anzahl der Pfade begrenzt, die die Abfrage für jeden Zwischenknoten berücksichtigt. Dazu teilen Sie eine Abfrage mit mehreren Schritten in mehrere MATCH-Anweisungen auf, die durch NEXT getrennt sind, und wenden ROW_NUMBER() am Mittelpunkt an, an dem Sie eine Stichprobe erstellen müssen:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
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;
Nächste Schritte
- Weitere Informationen zum Schreiben von Graphabfragen finden Sie in der Abfrageübersicht.
- Weitere Informationen zu Best Practices für Schemata.