Best practice per l'ottimizzazione delle query di Spanner Graph

Questo documento descrive le best practice per l'ottimizzazione delle prestazioni delle query Spanner Graph, che includono le seguenti ottimizzazioni:

  • Evita una scansione completa della tabella di input per nodi e archi.
  • Ridurre la quantità di dati che la query deve leggere dallo spazio di archiviazione.
  • Riduci le dimensioni dei dati intermedi.

Inizia dai nodi con cardinalità inferiore

Scrivi l'attraversamento del percorso in modo che inizi con i nodi a cardinalità inferiore. Questo approccio mantiene piccolo il set di risultati intermedi e velocizza l'esecuzione delle query.

Ad esempio, le seguenti query hanno la stessa semantica:

  • Attraversamento del bordo in avanti:

    GRAPH FinGraph
    MATCH (p:Person {name:"Alex"})-[:Owns]->(a:Account {is_blocked: true})
    RETURN p.id AS person_id, a.id AS account_id;
    
  • Attraversamento del bordo inverso:

    GRAPH FinGraph
    MATCH (a:Account {is_blocked:true})<-[:Owns]-(p:Person {name: "Alex"})
    RETURN p.id AS person_id, a.id AS account_id;
    

Supponendo che il numero di persone con il nome Alex sia inferiore al numero di account bloccati, ti consigliamo di scrivere questa query nella traversata degli archi in avanti.

Iniziare dai nodi con cardinalità inferiore è particolarmente importante per l'attraversamento di percorsi di lunghezza variabile. L'esempio seguente mostra il modo consigliato per trovare gli account che si trovano a tre trasferimenti da un determinato account.

GRAPH FinGraph
MATCH (:Account {id: 7})-[:Transfers]->{1,3}(a:Account)
RETURN a.id;

Specificare tutte le etichette per impostazione predefinita

Spanner Graph deduce i nodi e le etichette degli archi qualificanti se le etichette vengono omesse. Ti consigliamo di specificare le etichette per tutti i nodi e gli archi, se possibile, perché questa inferenza potrebbe non essere sempre possibile e potrebbe causare la scansione di più etichette del necessario.

Singola istruzione MATCH

L'esempio seguente trova gli account collegati da un massimo di tre trasferimenti dall'account specificato:

GRAPH FinGraph
MATCH (src:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id;

Nelle istruzioni MATCH

Specifica le etichette su nodi e archi quando si riferiscono allo stesso elemento, ma si trovano in istruzioni MATCH.

L'esempio seguente mostra questo approccio consigliato:

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;

Utilizzare IS_FIRST per ottimizzare le query

Puoi utilizzare la funzione IS_FIRST per migliorare il rendimento delle query campionando i bordi e limitando gli attraversamenti nei grafici. Questa funzione consente di gestire i nodi con cardinalità elevata e ottimizzare le query multihop.

Se la dimensione del campione specificata è troppo piccola, la query potrebbe non restituire dati. Per questo motivo, potresti dover provare diverse dimensioni del campione per trovare l'equilibrio ottimale tra i dati restituiti e il miglioramento delle prestazioni delle query.

Questi esempi di IS_FIRST utilizzano FinGraph, un grafico finanziario con Account nodi e Transfers archi per i trasferimenti di denaro. Per creare FinGraph e utilizzarlo per eseguire le query di esempio, consulta Configura ed esegui query su Spanner Graph.

Limita gli archi attraversati per migliorare le prestazioni delle query

Quando esegui query sui grafici, alcuni nodi possono avere un numero significativamente maggiore di archi in entrata o in uscita rispetto ad altri nodi. Questi nodi con cardinalità elevata vengono a volte chiamati super nodi o nodi hub. I super nodi possono causare problemi di prestazioni perché i relativi attraversamenti potrebbero comportare l'elaborazione di enormi quantità di dati, il che porta a una distorsione dei dati e a tempi di esecuzione lunghi.

Per ottimizzare una query di un grafico con supernodi, utilizza la funzione IS_FIRST all'interno di una clausola FILTER per limitare il numero di archi attraversati dalla query da un nodo. Poiché gli account in FinGraph potrebbero avere un numero di transazioni significativamente superiore rispetto ad altri, puoi utilizzare IS_FIRST per evitare una query inefficiente. Questa tecnica è particolarmente utile quando non è necessaria un'enumerazione completa di tutte le connessioni da un super nodo.

La seguente query trova gli account (a2) che ricevono trasferimenti direttamente o indirettamente da account bloccati (a1). La query utilizza IS_FIRST per evitare prestazioni lente quando un account ha molti trasferimenti limitando il numero di archi Transfers da considerare per ogni Account.

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;

Questo esempio utilizza quanto segue:

  • @max_transfers_per_account: un parametro di query che specifica il numero massimo di archi Transfers da considerare per ogni account (a1).

  • PARTITION BY SOURCE_NODE_ID(selected_e): garantisce che il limite di IS_FIRST venga applicato in modo indipendente per ogni account (a1).

  • ORDER BY selected_e.create_time DESC: specifica che vengono restituiti i trasferimenti più recenti.

Esegui il campionamento dei nodi intermedi per ottimizzare le query multihop

Puoi anche migliorare l'efficienza delle query utilizzando IS_FIRST per campionare i nodi intermedi nelle query multihop. Questa tecnica migliora l'efficienza limitando il numero di percorsi che la query considera per ogni nodo intermedio. Per farlo, suddividi una query multihop in più istruzioni MATCH separate da NEXT e applica IS_FIRST a metà percorso, dove devi campionare:

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;

Per capire come IS_FIRST ottimizza questa query:

  • La clausola FILTER IS_FIRST(1) OVER (PARTITION BY a2) viene applicata nella prima istruzione MATCH.

  • Per ogni nodo dell'account intermedio (a2), IS_FIRST considera solo il primo arco in entrata Transfers (e1), riducendo il numero di percorsi da esplorare nella seconda istruzione MATCH.

  • L'efficienza complessiva della query a due hop viene migliorata perché il secondo MATCH non elabora dati non necessari, soprattutto quando a2 ha molti trasferimenti in entrata.

Passaggi successivi