Best Practices für das Entwerfen eines Spanner-Graph-Schemas

In diesem Dokument wird beschrieben, wie Sie mithilfe von Best Practices effiziente Abfragen erstellen. zum Entwerfen von Spanner Graph-Schemas. Schemadesign kann iterativ sein. Wir empfehlen daher, dass Sie zuerst kritische Abfragemuster identifizieren, als Leitfaden für das Entwerfen des Schemas.

Allgemeine Informationen zu Best Practices für das Spanner-Schemadesign finden Sie unter Best Practices für Schemadesign.

Edge Traversal optimieren

Bei Edge Traversal wird der Prozess des Navigierens durch ein Diagramm anhand seines an einem bestimmten Knoten beginnen und sich entlang der miteinander verbundenen Kanten bewegen, um anderen Knoten. „Edge Traversal“ ist ein grundlegender Vorgang in Spanner Graph. Die Verbesserung der Effizienz beim Edge Traversal ist der Schlüssel zu Ihrer Anwendungsleistung.

Sie können eine Kante in zwei Richtungen durchlaufen: vom Quellknoten zu wird der Zielknoten als Forward Edge Traversal bezeichnet, während der Durchlauf Der Zielknoten zum Quellknoten wird als Reverse-Edge-Traversal bezeichnet.

Vorwärtskantendurchlauf mithilfe von Interleaving optimieren

Verschachteln Sie die Edge-Eingabetabelle, um die Leistung beim Forward-Edge-Traversal zu verbessern in die Eingabetabelle des Quellknotens ein, um die Kanten mit den Quellknoten zu verbinden. Verschachtelung ist eine Speicheroptimierungstechnik in Spanner, ordnet untergeordnete Tabellenzeilen den entsprechenden übergeordneten Zeilen in Speicherplatz. Weitere Informationen zur Verschränkung finden Sie unter Schemas

Das folgende Beispiel veranschaulicht diese Best Practices:

CREATE TABLE Person (
  id               INT64 NOT NULL,
  name             STRING(MAX),
) PRIMARY KEY (id);

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Reverse-Edge-Traversal mit Fremdschlüssel optimieren

Um Rückkanten effizient zu durchlaufen, erstellen Sie eine Fremdschlüsseleinschränkung zwischen Edge- und Zielknotens. Dieser Fremdschlüssel erstellt automatisch ein sekundärer Index am Edge und den Zielknotenschlüsseln ein. Der sekundäre Index ist die bei der Ausführung von Abfragen automatisch verwendet werden.

Das folgende Beispiel veranschaulicht diese Best Practices:

CREATE TABLE Person (
  id               INT64 NOT NULL,
  name             STRING(MAX),
) PRIMARY KEY (id);

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id);

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id),
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Reverse Edge Traversal mit sekundärem Index optimieren

Wenn Sie keinen Fremdschlüssel auf Edge-Geräten erstellen möchten, z. B. aufgrund des Datenintegrität erzwungen wird, können Sie direkt einen sekundären Index Edge-Eingabetabelle hinzu, wie im folgenden Beispiel gezeigt:

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE INDEX Reverse_PersonOwnAccount
ON PersonOwnAccount (account_id);

Hängende Kanten nicht zulassen

Eine hängende Kante ist eine Kante, die weniger als zwei Knoten verbindet. Ein baumelndes Edge kann auftreten, wenn ein Knoten gelöscht wird, ohne die zugehörigen Kanten zu entfernen, oder Wenn eine Kante erstellt wird, ohne sie richtig mit ihren Knoten zu verbinden.

Das Verhindern von hängenden Kanten bietet folgende Vorteile:

  • Erzwingt die Integrität der Grafikstruktur.
  • Verbessert die Abfrageleistung, da zusätzliche Arbeit zum Herausfiltern von Kanten vermieden wird bei denen keine Endpunkte vorhanden sind.

Hängende Kanten mit referenziellen Einschränkungen nicht zulassen

Um baumelnde Kanten zu verhindern, geben Sie Einschränkungen für beide an Endpunkte:

  • Verschachteln Sie die Edge-Eingabetabelle mit der Eingabetabelle des Quellknotens. Dieses stellt sicher, dass der Quellknoten einer Edge immer vorhanden ist.
  • Fremdschlüsseleinschränkung an Kanten erstellen, um sicherzustellen, dass der Zielknoten einer Kante immer existiert.

Im folgenden Beispiel werden Verschränkung und ein Fremdschlüssel verwendet, um referenzielle Integrität:

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

Verwenden Sie ON DELETE CASCADE, um beim Löschen eines Knotens automatisch Kanten zu entfernen.

Wenn Sie Verschachtelung oder einen Fremdschlüssel verwenden, um baumelnde Kanten zu verbieten, verwenden Sie die Methode ON DELETE, um das Verhalten beim Löschen eines Knotens mit die noch angebracht sind. Weitere Informationen finden Sie unter Kettenlöschung für verschränkte Tabellen und Kettenlöschung mit Fremdschlüsseln.

Sie können ON DELETE auf folgende Arten verwenden:

  • ON DELETE NO ACTION (oder ON DELETE-Klausel auslassen): Löschen eines mit Kanten schlägt fehl.
  • ON DELETE CASCADE: Durch das Löschen eines Knotens wird automatisch Folgendes entfernt: zugehörige Kanten in derselben Transaktion.

Kaskade für Kanten löschen, die verschiedene Knotentypen verbinden

  • Kanten löschen, wenn der Quellknoten gelöscht wird. Beispielsweise löscht INTERLEAVE IN PARENT Person ON DELETE CASCADE alle ausgehenden PersonOwnAccount Ränder vom Person-Knoten wird gelöscht. Weitere Informationen finden Sie unter Verschränkte Tabellen erstellen

  • Kanten löschen, wenn der Zielknoten gelöscht wird. Beispiel: CONSTRAINT FK_Account FOREIGN KEY(account_id) REFERENCES Account(id) ON DELETE CASCADE löscht alle eingehenden PersonOwnAccount-Ränder in den Account-Knoten ein, der gelöscht wird. Weitere Informationen finden Sie unter Fremdschlüssel:

Kaskade für Kanten löschen, die denselben Knotentyp verbinden

Wenn Quell- und Zielknoten einer Kante denselben Typ haben und die Kante in den Quellknoten verschachtelt ist, können Sie ON DELETE CASCADE nur für den Quell- oder Zielknoten definieren, aber nicht für beide Knoten.

Um in beiden Fällen automatisch hängende Kanten zu entfernen, erstellen Sie einen Fremdschlüssel auf Referenz des Edge-Quellknotens, anstatt die Edge-Eingabetabelle Quellknoten-Eingabetabelle.

Wir empfehlen Verschachtelung für „Forward-Edge Traversal“ optimieren. Prüfen Sie unbedingt die Auswirkungen auf Ihre Arbeitslasten, bevor Sie fortfahren. Weitere Informationen finden Sie in der Im folgenden Beispiel, in dem AccountTransferAccount als Edge-Eingabe verwendet wird Tabelle:

--Define two Foreign Keys, each on one end Node of Transfer Edge, both with ON DELETE CASCADE action:
CREATE TABLE AccountTransferAccount (
  id               INT64 NOT NULL,
  to_id            INT64 NOT NULL,
  amount           FLOAT64,
  create_time      TIMESTAMP NOT NULL,
  order_number     STRING(MAX),
  CONSTRAINT FK_FromAccount FOREIGN KEY (id) REFERENCES Account (id) ON DELETE CASCADE,
  CONSTRAINT FK_ToAccount FOREIGN KEY (to_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, to_id);

Nach Knoten- oder Edge-Attributen mit sekundären Indexen filtern

Sekundäre Indexe sind für eine effiziente Abfrageverarbeitung unerlässlich. Sie unterstützen schnelle Suche nach Knoten und Kanten basierend auf bestimmten Eigenschaftswerten, ohne die gesamte Diagrammstruktur durchlaufen zu müssen. Das ist wichtig, wenn arbeiten Sie mit großen Diagrammen, da alle Knoten und Kanten durchlaufen werden, sehr ineffizient sein.

Knoten nach Attribut schneller filtern

Um das Filtern nach Knotenattributen zu beschleunigen, erstellen Sie sekundäre Indexe auf Eigenschaften. Mit der folgenden Abfrage werden beispielsweise Konten für Alias. Ohne einen sekundären Index werden alle Account-Knoten entsprechend gescannt die Filterkriterien.

GRAPH FinGraph
MATCH (acct:Account)
WHERE acct.nick_name = "abcd"
RETURN acct.id;

Um die Abfrage zu beschleunigen, erstellen Sie einen sekundären Index für das gefilterte Attribut wie folgt: Beispiel:

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  is_blocked       BOOL,
  nick_name        STRING(MAX),
) PRIMARY KEY (id);

CREATE INDEX AccountByEmail
ON Account (nick_name);

Tipp:Verwenden Sie nach NULL gefilterte Indexe für dünnbesetzte Attribute. Weitere Informationen Siehe Indexierung von NULL-Werten deaktivieren.

Vorwärts-Edge-Traversal mit Filtern nach Edge-Eigenschaften beschleunigen

Wenn Sie einen Kantenknoten durchlaufen und dabei nach seinen Eigenschaften filtern, können Sie die Abfrage beschleunigen, indem Sie einen sekundären Index für die Kanteneigenschaften erstellen und den Index in den Quellknoten einfügen.

Mit der folgenden Abfrage werden beispielsweise Konten gefunden, die nach einem bestimmten Zeitraum zu einer bestimmten Person gehören:

GRAPH FinGraph
MATCH (person:Person)-[owns:Owns]->(acct:Account)
WHERE person.id = 1
  AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008")
RETURN acct.id;

Standardmäßig werden mit dieser Abfrage alle Kanten der angegebenen Person gelesen und dann die Kanten herausgefiltert, die die Bedingung für create_time erfüllen.

Das folgende Beispiel zeigt, wie Sie die Abfrageeffizienz verbessern können, indem Sie einen sekundären Index in der Referenz des Edge-Quellknotens (id) und das Edge-Attribut (create_time). Index unter der Eingabetabelle des Quellknotens verschachteln, um Fügen Sie den Index mit dem Quellknoten zusammen.

CREATE TABLE PersonOwnAccount (
  id               INT64 NOT NULL,
  account_id       INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE INDEX PersonOwnAccountByCreateTime
ON PersonOwnAccount (id, create_time)
INTERLEAVE IN Person;

Mit diesem Ansatz kann die Abfrage effizient alle Kanten finden, die die Bedingung für create_time.

Durch Filterung nach Kanteneigenschaften die umgekehrte Kantendurchquerung beschleunigen

Wenn Sie eine umgekehrte Kante durchlaufen, während Sie nach ihren Eigenschaften filtern, können Sie die Abfrage zu beschleunigen, indem Sie mithilfe des Zielknotens einen sekundären Index Edge-Eigenschaften zum Filtern hinzufügen.

Die folgende Beispielabfrage führt einen umgekehrten Edge-Traversal mit Filterung durch Edge-Eigenschaften:

GRAPH FinGraph
MATCH (acct:Account)<-[owns:Owns]-(person:Person)
WHERE acct.id = 1
  AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008") 
RETURN person.id;

Sie können diese Abfrage mit einem sekundären Index beschleunigen. Verwenden Sie dazu eine der folgenden Optionen:

  • Sekundären Index in der Referenz des Edge-Zielknotens erstellen (account_id) und die Edge-Eigenschaft (create_time), wie in den folgendes Beispiel:

    CREATE TABLE PersonOwnAccount (
      id               INT64 NOT NULL,
      account_id       INT64 NOT NULL,
      create_time      TIMESTAMP,
    ) PRIMARY KEY (id, account_id),
      INTERLEAVE IN PARENT Person ON DELETE CASCADE;
    
    CREATE INDEX PersonOwnAccountByCreateTime
    ON PersonOwnAccount (account_id, create_time);
    

    Dieser Ansatz bietet eine bessere Leistung, da die umgekehrten Kanten nach account_id und create_time sortiert werden. So kann die Abfragemaschine effizienter Kanten für account_id finden, die die Bedingung für create_time erfüllen. Wenn jedoch mit unterschiedlichen Abfragemustern ist möglicherweise für jedes Attribut ein separater Index erforderlich, der Mehraufwand.

  • Sekundären Index in der Referenz des Edge-Zielknotens erstellen (account_id) und speichern Sie das Edge-Attribut (create_time) in einem Speicherspalte Dies wird im folgenden Beispiel gezeigt:

    CREATE TABLE PersonOwnAccount (
      id               INT64 NOT NULL,
      account_id       INT64 NOT NULL,
      create_time      TIMESTAMP,
    ) PRIMARY KEY (id, account_id),
      INTERLEAVE IN PARENT Person ON DELETE CASCADE;
    
    CREATE INDEX PersonOwnAccountByCreateTime
    ON PersonOwnAccount (account_id) STORING (create_time);
    

    Bei diesem Ansatz können mehrere Eigenschaften gespeichert werden. Die Abfrage muss jedoch alle Kanten des Zielknotens lesen und dann nach Edge-Eigenschaften filtern.

Sie können diese Ansätze miteinander kombinieren, indem Sie sich an die folgenden Richtlinien halten:

  • Verwenden Sie Edge-Attribute in Indexspalten, wenn sie in leistungskritische Abfragen.
  • Fügen Sie Attribute, die in weniger leistungssensiblen Abfragen verwendet werden, den Speicherspalten hinzu.

Modellknoten- und Edgetypen mit Labels und Attributen

Knoten- und Edge-Typen werden normalerweise mit Labels modelliert. Sie können jedoch auch zu Modelltypen hinzufügen. Nehmen wir ein Beispiel mit vielen verschiedenen Kontotypen wie BankAccount, InvestmentAccount und RetirementAccount Sie können die Konten in separaten Eingabetabellen speichern und als separate Labels modellieren oder die Konten in einer einzigen Eingabe speichern und verwenden Sie eine Eigenschaft, um zwischen den Typen zu unterscheiden.

Beginnen Sie den Modellierungsprozess, indem Sie die Typen mit Labels modellieren. Erwägen Sie in den folgenden Szenarien verwenden.

Schemaverwaltung verbessern

Wenn das Diagramm viele verschiedene Knoten- und Kantentypen hat, ist die Verwaltung einer separaten Eingabe kann es schwierig werden. Um die Schemaverwaltung zu vereinfachen, den Typ als Eigenschaft an.

Modelltypen in einer Property, um sich häufig ändernde Typen zu verwalten

Wenn Sie Typen als Labels modellieren, müssen Sie das Schema ändern, wenn Sie Typen hinzufügen oder entfernen möchten. Wenn Sie in kurzer Zeit zu viele Schemaaktualisierungen durchführen, Spanner könnte throttle die Verarbeitung von Schemaaktualisierungen in der Warteschlange. Weitere Informationen finden Sie unter Häufigkeit von Schemaaktualisierungen begrenzen.

Wenn Sie das Schema häufig ändern müssen, empfehlen wir, dass Sie das Modell des Geben Sie eine Eigenschaft ein, um Einschränkungen bei der Häufigkeit von Schemas zu umgehen. Aktualisierungen.

Abfragen beschleunigen

Modellierungstypen mit Attributen können Abfragen beschleunigen, wenn der Knoten- oder Edge-Muster auf mehrere Labels verweist. Mit der folgenden Beispielabfrage werden alle Instanzen von SavingsAccount und InvestmentAccount gefunden, die zu einem Person gehören. Dabei wird davon ausgegangen, dass Kontotypen mit Labels modelliert sind:

GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:SavingsAccount|InvestmentAccount)
RETURN acct.id;

Das Knotenmuster acct verweist auf zwei Labels. Wenn dies ein leistungskritische Abfrage sollten Sie die Account anhand einer Property modellieren. Dieser Ansatz kann zu einer besseren Abfrageleistung führen, wie das folgende Abfragebeispiel zeigt. Wir empfehlen, beide Abfragen zu vergleichen.

GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:Account)
WHERE acct.type IN ("Savings", "Investment")
RETURN acct.id;

Speichern Sie den Typ im Knotenelementschlüssel, um Abfragen zu beschleunigen

Beschleunigen von Abfragen durch Filtern des Knotentyps, wenn ein Knotentyp modelliert wird mit einer Eigenschaft verwenden und der Typ sich während der Knotenlebensdauer nicht ändert, folgen Sie diese Schritte:

  1. Fügen Sie das Attribut als Teil des Knotenelementschlüssels ein.
  2. Fügen Sie den Knotentyp in die Edge-Eingabetabelle ein.
  3. Fügen Sie den Knotentyp in die Schlüssel für die Kantenreferenzen ein.

Im folgenden Beispiel wird diese Optimierung auf den Knoten Account und den Rand AccountTransferAccount.

CREATE TABLE Account (
  type             STRING(MAX) NOT NULL,
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
) PRIMARY KEY (type, id);

CREATE TABLE AccountTransferAccount (
  type             STRING(MAX) NOT NULL,
  id               INT64 NOT NULL,
  to_type          STRING(MAX) NOT NULL,
  to_id            INT64 NOT NULL,
  amount           FLOAT64,
  create_time      TIMESTAMP NOT NULL,
  order_number     STRING(MAX),
) PRIMARY KEY (type, id, to_type, to_id),
  INTERLEAVE IN PARENT Account ON DELETE CASCADE;

CREATE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Account
  )
  EDGE TABLES (
    AccountTransferAccount
      SOURCE KEY (type, id) REFERENCES Account
      DESTINATION KEY (to_type, to_id) REFERENCES Account
  );

TTL auf Knoten und Edges konfigurieren

Spanner Die Gültigkeitsdauer (TTL) ist ein Mechanismus, der automatische Ablauf und Löschen von Daten nach Ablauf eines bestimmten Zeitraums. Dies wird häufig für Daten verwendet, Lebensdauer oder Relevanz, wie Sitzungsinformationen, temporäre Caches oder Ereignisse Logs. In diesen Fällen hilft TTL dabei, die Datenbankgröße und -leistung aufrechtzuerhalten.

Im folgenden Beispiel werden Konten mithilfe der TTL 90 Tage nach der Sperrung:

CREATE TABLE Account (
  id               INT64 NOT NULL,
  create_time      TIMESTAMP,
  close_time       TIMESTAMP,
) PRIMARY KEY (id),
  ROW DELETION POLICY (OLDER_THAN(close_time, INTERVAL 90 DAY));

Wenn die Knotentabelle eine TTL hat und eine Edge-Tabelle darin verschränkt ist, Verschränkung muss definiert werden mit ON DELETE CASCADE Ähnlich verhält es sich, wenn die Knotentabelle eine TTL hat und von einer Edge-Tabelle referenziert wird. durch einen Fremdschlüssel muss der Fremdschlüssel mit ON DELETE CASCADE

Im folgenden Beispiel wird AccountTransferAccount bis zu zehn Jahre lang gespeichert. solange ein Konto aktiv bleibt. Wenn ein Konto gelöscht wird, wird die Übertragung wird ebenfalls gelöscht.

CREATE TABLE AccountTransferAccount (
  id               INT64 NOT NULL,
  to_id            INT64 NOT NULL,
  amount           FLOAT64,
  create_time      TIMESTAMP NOT NULL,
  order_number     STRING(MAX),
) PRIMARY KEY (id, to_id),
  INTERLEAVE IN PARENT Account ON DELETE CASCADE,
  ROW DELETION POLICY (OLDER_THAN(create_time, INTERVAL 3650 DAY));

Knoten- und Edge-Eingabetabellen zusammenführen

Sie können mit derselben Eingabetabelle mehr als einen Knoten und eine Kante in Ihrem Schema.

In den folgenden Beispieltabellen haben die Account-Knoten einen zusammengesetzten Schlüssel (owner_id, account_id). Es gibt eine implizite Edge-Definition: Person-Knoten mit Schlüssel (id) besitzt den Account-Knoten mit zusammengesetztem Schlüssel (owner_id, account_id), wenn id gleich owner_id ist.

CREATE TABLE Person (
  id INT64 NOT NULL,
) PRIMARY KEY (id);

-- Assume each account has exactly one owner.
CREATE TABLE Account (
  owner_id INT64 NOT NULL,   
  account_id INT64 NOT NULL,        
) PRIMARY KEY (owner_id, account_id);

In diesem Fall können Sie die Account-Eingabetabelle verwenden, um den Account zu definieren. Knoten und PersonOwnAccount-Edge, wie im folgenden Schemabeispiel gezeigt. Um sicherzustellen, dass alle Elementtabellennamen eindeutig sind, wird im Beispiel der Rand Tabellendefinition den Alias Owns.

CREATE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person,
    Account
  )
  EDGE TABLES (
    Account AS Owns
      SOURCE KEY (owner_id) REFERENCES Person
      DESTINATION KEY (owner_id, account_id) REFERENCES Account
  );

Nächste Schritte