<ph type="x-smartling-placeholder">
Ce document explique comment créer des requêtes efficaces en suivant les bonnes pratiques de conception des schémas de graphiques Spanner. La conception de schémas peut être itératif, c'est pourquoi nous vous recommandons de commencer par identifier les schémas de requête critiques. pour concevoir votre schéma.
Pour obtenir des informations générales sur la conception de schémas Spanner, consultez la section Bonnes pratiques pour la conception de schémas.
Optimiser le balayage en périphérie
Le balayage par les bords consiste à parcourir un graphique en suivant en partant d'un nœud spécifique et en suivant des arêtes connectées d'autres nœuds. La traversée de bords est une opération fondamentale dans Spanner Graph. Par conséquent, améliorer l'efficacité de la traversée de bords est essentiel pour les performances de votre application.
Vous pouvez balayer une arête dans deux directions: en passant du nœud source le nœud de destination est appelé balayage de bord avant, tandis que le passage depuis le nœud de destination au nœud source est appelé balayage de bord inverse.
Optimiser la traversée de l'arête avant à l'aide de l'entrelacement
Entrelacer la table d'entrée périphérique pour améliorer les performances de balayage dans la table d'entrée du nœud source pour colocaliser les arêtes avec les nœuds sources. L'entrelacement est une technique d'optimisation du stockage dans Spanner qui place physiquement les lignes de table enfant avec leurs lignes parentes correspondantes dans l'espace de stockage. Pour en savoir plus sur l'entrelacement, consultez la section Présentation des schémas.
L'exemple suivant illustre ces bonnes pratiques:
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;
Optimiser le balayage inverse du bord à l'aide d'une clé étrangère
Pour balayer efficacement les arêtes inversées, créez un contrainte de clé étrangère entre entre le périphérique et le nœud de destination. Cette clé étrangère crée automatiquement un index secondaire sur l'arc associé aux clés de nœud de destination. L'index secondaire est automatiquement utilisés lors de l'exécution de la requête.
L'exemple suivant illustre ces bonnes pratiques:
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;
Optimiser le balayage de bord inverse à l'aide d'un index secondaire
Si vous ne souhaitez pas créer de clé étrangère sur le bord, par exemple en raison de l'intégrité stricte des données qu'elle applique, vous pouvez créer directement un indice secondaire sur la table d'entrée de bord, comme illustré dans l'exemple suivant :
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);
Interdire les bords suspendus
Une arête pendante est une arête qui relie moins de deux nœuds. Une créature qui pend peut se produire lorsqu'un nœud est supprimé sans retirer les arêtes qui lui sont associées ; ou lorsqu'une arête est créée sans la lier correctement à ses nœuds.
L'interdiction des bords non connectés offre les avantages suivants :
- Applique l'intégrité de la structure du graphique.
- Améliore les performances des requêtes en évitant le travail supplémentaire de filtrage des arêtes où les points de terminaison n'existent pas.
Interdire les arêtes sans extrémité à l'aide de contraintes référentielles
Pour interdire les arêtes pendantes, spécifiez des contraintes sur les deux points de terminaison :
- Entrelacer la table d'entrée de périphérie dans la table d'entrée du nœud source Cette approche garantit que le nœud source d'une arête existe toujours.
- Créez une contrainte de clé étrangère sur les arêtes pour vous assurer que le nœud de destination d'une arête existe toujours.
L'exemple suivant utilise l'entrelacement et une clé étrangère pour appliquer l'intégrité référentielle :
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;
Utiliser ON DELETE CASCADE pour supprimer automatiquement les arêtes lors de la suppression d'un nœud
Lorsque vous utilisez l'intercalation ou une clé étrangère pour interdire les arêtes pendantes, utilisez la clause ON DELETE
pour contrôler le comportement lorsque vous souhaitez supprimer un nœud avec des arêtes encore attachées. Pour en savoir plus, consultez
Supprimer l'en cascade pour les tables entrelacées
et
supprimer les cascading avec des clés étrangères.
Vous pouvez utiliser ON DELETE
des manières suivantes:
ON DELETE NO ACTION
(ou omission de la clauseON DELETE
) : la suppression d'un nœud avec des arêtes échouera.ON DELETE CASCADE
: la suppression d'un nœud supprime automatiquement le associées dans la même transaction.
Cascade de suppression pour les arêtes reliant différents types de nœuds
Supprimer les arêtes lorsque le nœud source est supprimé. Par exemple,
INTERLEAVE IN PARENT Person ON DELETE CASCADE
supprime tous les appelsPersonOwnAccount
arêtes à partir du nœudPerson
en cours de suppression. Pour plus pour en savoir plus, consultez Créer des tables entrelacéesSupprimer les arêtes lorsque le nœud de destination est supprimé. Par exemple,
CONSTRAINT FK_Account FOREIGN KEY(account_id) REFERENCES Account(id) ON DELETE CASCADE
supprime toutes les arêtesPersonOwnAccount
entrantes dans le nœudAccount
en cours de suppression. Pour en savoir plus, consultez Clés étrangères :
Supprimer la cascade pour les arêtes connectant le même type de nœuds
Lorsque les nœuds source et de destination d'une arête ont le même type et que le
est entrelacé dans le nœud source, vous pouvez définir ON DELETE CASCADE
uniquement pour le nœud source ou de destination (mais pas les deux).
Pour supprimer automatiquement les arêtes sans extrémité dans les deux cas, créez une clé étrangère sur la référence du nœud source de l'arête au lieu d'intercaler la table d'entrée de l'arête dans la table d'entrée du nœud source.
Nous vous recommandons d'entrelacer
optimiser le balayage avant.
Assurez-vous de vérifier l'impact sur vos charges de travail avant de continuer. Consultez le
dans l'exemple suivant, qui utilise AccountTransferAccount
comme entrée périphérique
tableau:
--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);
Filtrer par propriété de nœud ou de périphérie avec des index secondaires
Les index secondaires sont essentiels pour un traitement efficace des requêtes. Ils permettent des recherches rapides de nœuds et d'arêtes en fonction de valeurs de propriété spécifiques, sans avoir à parcourir l'ensemble de la structure du graphique. C'est important quand vous travaillez avec de grands graphiques, car le balayage de tous les nœuds et arêtes peut s'avérer très inefficace.
Accélérer le filtrage des nœuds par propriété
Pour accélérer le filtrage par propriétés de nœud, créez des index secondaires sur les propriétés. Par exemple, la requête suivante recherche les comptes
Pseudo. Sans indice secondaire, tous les nœuds Account
sont analysés pour correspondre aux critères de filtrage.
GRAPH FinGraph
MATCH (acct:Account)
WHERE acct.nick_name = "abcd"
RETURN acct.id;
Pour accélérer la requête, créez un indice secondaire sur la propriété filtrée, comme indiqué dans l'exemple suivant :
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);
Conseil : Utilisez des index filtrés par NULL pour les propriétés peu denses. Pour en savoir plus, consultez la section Désactiver l'indexation des valeurs NULL.
Accélérez la traversée des bords avant avec le filtrage des propriétés de bord
Lorsque vous parcourez une arête en filtrant sur ses propriétés, vous pouvez accélérer la requête en créant un indice secondaire sur les propriétés de l'arête et en intercalant l'indice dans le nœud source.
Par exemple, la requête suivante recherche les comptes appartenant à une personne donnée après un certain temps :
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;
Par défaut, cette requête lit tous les bords de la personne spécifiée, puis filtre les bords qui répondent à la condition sur create_time
.
L'exemple suivant montre comment améliorer l'efficacité des requêtes en créant un indice secondaire sur la référence du nœud source de l'arc (id
) et la propriété de l'arc (create_time
). Intercalez l'index sous la table d'entrée du nœud source pour le placer à côté du nœud source.
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;
Grâce à cette approche, la requête peut trouver efficacement tous les bords qui satisfont la condition sur create_time
.
Accélérer la traversée des bords inverses avec le filtrage des propriétés de bord
Lorsque vous parcourez une arête inverse en filtrant sur ses propriétés, vous pouvez accélérer la requête en créant un indice secondaire à l'aide du nœud de destination et des propriétés de l'arête pour le filtrage.
L'exemple de requête suivant effectue un balayage de bord inverse avec filtrage sur Propriétés de périphérie:
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;
Pour accélérer cette requête à l'aide d'un index secondaire, utilisez l'une des méthodes suivantes : options:
Créez un indice secondaire sur la référence du nœud de destination de l'edge (
account_id
) et la propriété de l'edge (create_time
), comme illustré dans l'exemple suivant :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);
Cette approche offre de meilleures performances, car les arêtes inversées triées par
account_id
etcreate_time
, ce qui permet au moteur de requêtes trouver efficacement des arêtes pouraccount_id
qui remplissent la condition surcreate_time
Toutefois, si différents modèles de requêtes filtrent sur différentes propriétés, chaque propriété peut nécessiter un indice distinct, ce qui peut entraîner des coûts supplémentaires.Créer un index secondaire sur la référence du nœud de destination périphérique (
account_id
) et stockez la propriété de périphérie (create_time
) dans un colonne de stockage, comme illustré dans l'exemple suivant: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);
Avec cette approche, vous pouvez stocker plusieurs propriétés. Toutefois, la requête doit lire toutes les arêtes du nœud de destination, puis filtrer les propriétés des arêtes.
Vous pouvez combiner ces approches en suivant les consignes ci-dessous:
- Utilisez les propriétés de périphérie dans les colonnes d'index si elles sont utilisées dans les requêtes critiques pour les performances.
- Pour les propriétés utilisées dans les requêtes moins sensibles aux performances, ajoutez-les dans les colonnes de stockage.
Modéliser des types de nœuds et d'arêtes avec des étiquettes et des propriétés
Les types de nœuds et d'arêtes sont généralement modélisés à l'aide de libellés. Toutefois, vous pouvez également utiliser des propriétés pour modéliser des types. Prenons l'exemple d'un cas où il existe de nombreux types de comptes, comme BankAccount
, InvestmentAccount
et RetirementAccount
. Vous pouvez stocker les comptes dans des tables d'entrée distinctes et les modéliser en tant que libellés distincts, ou stocker les comptes dans une seule table d'entrée et utiliser une propriété pour différencier les types.
Commencez le processus de modélisation en modélisant les types avec des étiquettes. Envisagez d'utiliser à l'aide de propriétés dans les scénarios suivants.
Améliorer la gestion des schémas
Si votre graphique comporte de nombreux types de nœuds et d'arêtes différents, gérer une entrée distincte pour chacune d'elles peut s'avérer difficile. Pour faciliter la gestion du schéma, modélisez le type en tant que propriété.
Modéliser des types dans une propriété pour gérer les types qui changent fréquemment
Lorsque vous modélisez des types en tant que libellés, l'ajout ou la suppression de types nécessite des modifications du schéma. Si vous effectuez trop de mises à jour de schéma sur une courte période, Spanner peut limiter le traitement des mises à jour de schéma en file d'attente. Pour en savoir plus, consultez Limitez la fréquence des mises à jour du schéma.
Si vous devez modifier fréquemment le schéma, nous vous recommandons de modéliser la dans une propriété pour contourner les limites de fréquence du schéma mises à jour.
Accélérer les requêtes
Modéliser des types avec des propriétés peut accélérer les requêtes lorsque le modèle de nœud ou d'arête fait référence à plusieurs libellés. L'exemple de requête suivant recherche toutes les instances de
SavingsAccount
et InvestmentAccount
appartenant à un Person
, en supposant que le compte
sont modélisés avec des étiquettes:
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:SavingsAccount|InvestmentAccount)
RETURN acct.id;
Le modèle de nœud acct
fait référence à deux libellés. S'il s'agit d'un
requête critique pour les performances, envisagez de modéliser Account
à l'aide d'une propriété. Cette approche peut améliorer les performances des requêtes, comme illustré dans l'exemple de requête suivant. Nous vous recommandons d'effectuer une analyse comparative des deux requêtes.
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:Account)
WHERE acct.type IN ("Savings", "Investment")
RETURN acct.id;
Stockez le type dans la clé de l'élément de nœud pour accélérer les requêtes
Pour accélérer les requêtes grâce au filtrage par type de nœud lorsqu'un type de nœud est modélisé avec une propriété dont le type ne change pas pendant la durée de vie du nœud, procédez comme suit:
- Incluez la propriété dans la clé de l'élément de nœud.
- Ajoutez le type de nœud à la table d'entrée Edge.
- Incluez le type de nœud dans les clés de référencement Edge.
L'exemple suivant applique cette optimisation au nœud Account
et à l'arête 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
);
Configurer le TTL sur les nœuds et les arêtes
La valeur TTL (Time To Live) de Spanner est un mécanisme qui permet l'expiration et la suppression automatiques des données après un certain temps. Il est souvent utilisé pour les données ayant une durée de vie ou pertinence (informations sur la session, caches temporaires, événements journaux. Dans ces cas, la valeur TTL permet de maintenir la taille et les performances de la base de données.
L'exemple suivant utilise la valeur TTL pour supprimer des comptes 90 jours après leur fermeture:
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));
Si la table de nœuds comporte une valeur TTL et une table périphérique entrelacée, la
entrelacement doit être défini avec
ON DELETE CASCADE
De même, si la table de nœuds a une valeur TTL et est référencée par une table périphérique
par le biais d'une clé étrangère, celle-ci doit être définie avec
ON DELETE CASCADE
Dans l'exemple suivant, AccountTransferAccount
est stocké pendant dix ans au maximum tant qu'un compte reste actif. Lorsqu'un compte est supprimé, l'historique des transferts l'est également.
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));
Fusionner les tables d'entrée de nœuds et de périphérie
Vous pouvez utiliser la même table d'entrée pour définir plusieurs nœuds et arêtes dans votre du schéma.
Dans les exemples de tableaux suivants, les nœuds Account
ont une clé composite (owner_id, account_id)
. Il existe une définition d'arête implicite : le nœud Person
avec la clé (id
) est propriétaire du nœud Account
avec clé composite.
(owner_id, account_id)
lorsque id
est égal à owner_id
.
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);
Dans ce cas, vous pouvez utiliser le tableau d'entrée Account
pour définir le nœud Account
et l'arête PersonOwnAccount
, comme illustré dans l'exemple de schéma suivant.
Pour vous assurer que tous les noms de tables d'éléments sont uniques, l'exemple attribue à la définition de la table de bordure l'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
);
Étape suivante
- Créez, mettez à jour ou supprimez un schéma de graphique Spanner.
- Insérez, mettez à jour ou supprimez des données de graphique Spanner.