Práticas recomendadas para otimizar as consultas do Spanner Graph

Este documento descreve as práticas recomendadas para otimizar o desempenho das consultas do Spanner Graph, que incluem as seguintes otimizações:

  • Evite uma análise completa da tabela de entrada para nós e arestas.
  • Reduzir a quantidade de dados que a consulta tem de ler do armazenamento.
  • Reduza o tamanho dos dados intermédios.

Comece por nós de cardinalidade inferior

Escreva a travessia do caminho de modo que comece pelos nós de cardinalidade inferior. Esta abordagem mantém o conjunto de resultados intermédios pequeno e acelera a execução da consulta.

Por exemplo, as seguintes consultas têm a mesma semântica:

  • Deslocamento de arestas para a frente:

    GRAPH FinGraph
    MATCH (p:Person {name:"Alex"})-[:Owns]->(a:Account {is_blocked: true})
    RETURN p.id AS person_id, a.id AS account_id;
    
  • Inversão da travessia de arestas:

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

Partindo do princípio de que existem menos pessoas com o nome Alex do que contas bloqueadas, recomendamos que escreva esta consulta na travessia de arestas para a frente.

Começar por nós de cardinalidade inferior é especialmente importante para a travessia de caminhos de comprimento variável. O exemplo seguinte mostra a forma recomendada de encontrar contas que estão a três transferências de uma determinada conta.

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

Especificar todas as etiquetas por predefinição

O gráfico do Spanner infere os nós e as etiquetas de arestas elegíveis se as etiquetas forem omitidas. Recomendamos que especifique etiquetas para todos os nós e arestas, sempre que possível, porque esta inferência pode nem sempre ser possível e pode fazer com que sejam analisadas mais etiquetas do que o necessário.

Declaração CORRESP única

O exemplo seguinte encontra contas associadas por, no máximo, 3 transferências da conta especificada:

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

Em declarações CORRESP

Especifique etiquetas em nós e arestas quando se referem ao mesmo elemento, mas estão em várias declarações MATCH.

O exemplo seguinte mostra esta abordagem recomendada:

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;

Use IS_FIRST para otimizar consultas

Pode usar a função IS_FIRST para melhorar o desempenho das consultas através da amostragem de arestas e da limitação de travessias em gráficos. Esta função ajuda a processar nós de cardinalidade elevada e a otimizar consultas de vários saltos.

Se o tamanho da amostra especificado for demasiado pequeno, a consulta pode não devolver dados. Por este motivo, pode ter de experimentar diferentes tamanhos de amostra para encontrar o equilíbrio ideal entre os dados devolvidos e o desempenho melhorado das consultas.

Estes exemplos de IS_FIRST usam FinGraph, um gráfico financeiro com Account nós e Transfers arestas para transferências de dinheiro. Para criar o FinGraph e usá-lo para executar as consultas de exemplo, consulte Configure e consulte o Spanner Graph.

Limite as arestas percorridas para melhorar o desempenho das consultas

Quando consulta gráficos, alguns nós podem ter um número significativamente maior de arestas de entrada ou saída em comparação com outros nós. Por vezes, estes nós de alta cardinalidade são denominados supernós ou nós centrais. Os nós super podem causar problemas de desempenho porque as travessias através deles podem envolver o processamento de grandes quantidades de dados, o que leva a uma distorção dos dados e a longos tempos de execução.

Para otimizar uma consulta de um gráfico com supernós, use a função IS_FIRST numa cláusula FILTER para limitar o número de arestas que a consulta atravessa a partir de um nó. Uma vez que as contas no FinGraph podem ter um número significativamente superior de transações do que outras, pode usar IS_FIRST para evitar uma consulta ineficiente. Esta técnica é particularmente útil quando não precisa de uma enumeração completa de todas as associações a partir de um supernó.

A seguinte consulta encontra contas (a2) que recebem transferências direta ou indiretamente de contas bloqueadas (a1). A consulta usa IS_FIRST para evitar um desempenho lento quando uma conta tem muitas transferências, limitando o número de associações Transfers a considerar para cada 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;

Este exemplo usa o seguinte:

  • @max_transfers_per_account: um parâmetro de consulta que especifica o número máximo de arestas Transfers a considerar para cada conta (a1).

  • PARTITION BY SOURCE_NODE_ID(selected_e): garante que o limite de IS_FIRST se aplica independentemente a cada conta (a1).

  • ORDER BY selected_e.create_time DESC: especifica que são devolvidas as transferências mais recentes.

Exemplo de nós intermédios para otimizar consultas de vários passos

Também pode melhorar a eficiência das consultas usando IS_FIRST para amostrar nós intermédios em consultas de vários passos. Esta técnica melhora a eficiência limitando o número de caminhos que a consulta considera para cada nó intermédio. Para tal, divida uma consulta de vários passos em várias declarações MATCH separadas por NEXT e aplique IS_FIRST no ponto médio onde precisa de fazer a amostragem:

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;

Para compreender como o IS_FIRST otimiza esta consulta:

  • A cláusula FILTER IS_FIRST(1) OVER (PARTITION BY a2) é aplicada na primeira declaração MATCH.

  • Para cada nó de conta intermédio (a2), IS_FIRST considera apenas a primeira aresta de entrada Transfers (e1), o que reduz o número de caminhos a explorar na segunda declaração MATCH.

  • A eficiência geral da consulta de dois saltos é melhorada porque o segundo MATCH não processa dados desnecessários, especialmente quando a2 tem muitas transferências recebidas.

O que se segue?