Best practices for tuning Spanner Graph queries

This document describes best practices for tuning Spanner Graph query performance, which include the following optimizations:

  • Avoid a full scan of the input table for nodes and edges.
  • Reduce the amount of data the query needs to read from storage.
  • Reduce the size of intermediate data.

Start from lower cardinality nodes

Write the path traversal so that it starts with the lower cardinality nodes. This approach keeps the intermediate result set small, and speeds up query execution.

For example, the following queries have the same semantics:

  • Forward edge traversal:

    GRAPHFinGraph
    MATCH(p:Person{name:"Alex"})-[:Owns]->(a:Account{is_blocked:true})
    RETURNp.idASperson_id,a.idASaccount_id;
    
  • Reverse edge traversal:

    GRAPHFinGraph
    MATCH(a:Account{is_blocked:true})<-[:Owns]-(p:Person{name:"Alex"})
    RETURNp.idASperson_id,a.idASaccount_id;
    

Assuming that there are fewer people with the name Alex than there are blocked accounts, we recommend that you write this query in the forward edge traversal.

Starting from lower cardinality nodes is especially important for variable-length path traversal. The following example shows the recommended way to find accounts that are within three transfers of a given account.

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

Specify all labels by default

Spanner Graph infers the qualifying nodes and edge labels if labels are omitted. We recommend that you specify labels for all nodes and edges where possible, because this inference might not always be possible and it might cause more labels than necessary to be scanned.

Single MATCH statement

The following example finds accounts linked by at most 3 transfers from the given account:

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

Across MATCH statements

Specify labels on nodes and edges when they refer to the same element but are across MATCH statements.

The following example shows this recommended approach:

GRAPHFinGraph
MATCH(acct:Account{id:7})-[:Transfers]->{1,3}(other_acct:Account)
RETURNacct,COUNT(DISTINCTother_acct)ASrelated_accts
GROUPBYacct
NEXT
MATCH(acct:Account)<-[:Owns]-(p:Person)
RETURNp.idASperson,acct.idASacct,related_accts;

What's next

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025年10月13日 UTC.