Questo documento descrive come creare query efficienti utilizzando le best practice per la progettazione degli schemi di Spanner Graph. La progettazione dello schema può in modo iterativo, per cui ti consigliamo di identificare prima i pattern di query per la progettazione dello schema.
Per informazioni generali sulla progettazione dello schema Spanner consulta le Best practice per la progettazione di schemi.
Ottimizza l'attraversamento dei bordi
La percorrenza degli spigoli è il processo di navigazione in un grafo seguendo i suoi spigoli, partendo da un determinato nodo e spostandosi lungo gli spigoli collegati per raggiungere altri nodi. L'attraversamento perimetrale è un'operazione fondamentale nel grafico di Spanner, il miglioramento dell'efficienza dell'attraversamento perimetrale è fondamentale per le prestazioni dell'applicazione.
Puoi attraversare un bordo in due direzioni: dal nodo di origine a il nodo di destinazione è chiamato forward edge traversal, mentre attraversa dal nodo di destinazione a quello di origine è detto inverti attraversamento.
Ottimizza l'esplorazione dell'edge in avanti utilizzando l'interlacciamento
Per migliorare le prestazioni dell'attraversamento in avanti, utilizza l'interfoliazione della tabella di input dell'edge nella tabella di input del nodo di origine per collocare gli bordi con i nodi di origine. L'interlacciamento è una tecnica di ottimizzazione dello spazio di archiviazione in Spanner che colloca fisicamente le righe delle tabelle figlio con le righe principali corrispondenti nello spazio di archiviazione. Per ulteriori informazioni sull'interleaving, vedi Panoramica degli schemi.
L'esempio seguente mostra queste best practice:
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;
Ottimizza l'attraversamento inverso utilizzando una chiave esterna
Per attraversare in modo efficiente i bordi inversi, crea un vincolo di chiave esterna tra tra il perimetro e il nodo di destinazione. Questa chiave esterna crea automaticamente indice secondario sul perimetro bloccato dalle chiavi del nodo di destinazione. L'indice secondario viene utilizzato automaticamente durante l'esecuzione della query.
L'esempio seguente mostra queste best practice:
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;
Ottimizzare il traversale degli archi in senso inverso utilizzando l'indice secondario
Se non vuoi creare una chiave esterna nell'edge, ad esempio a causa dell'integrità rigorosa dei dati che applica, puoi creare direttamente un indice secondario nella tabella di input dell'edge, come mostrato nell'esempio seguente:
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);
Non consentire bordi sporgenti
Un bordo pendente è un bordo che collega meno di due nodi. Una penzola un perimetro può verificarsi quando un nodo viene eliminato senza rimuovere i bordi associati quando viene creato un perimetro senza collegarlo correttamente ai suoi nodi.
La disattivazione degli spigoli sporgenti offre i seguenti vantaggi:
- Forza l'integrità della struttura del grafico.
- Migliora le prestazioni delle query evitando il lavoro aggiuntivo necessario per filtrare i bordi dove non esistono endpoint.
Non consentire i bordi pendenti usando i vincoli referenziali
Per non consentire bordi sporgenti, specifica vincoli su entrambi gli endpoint:
- Intercala la tabella di input dell'elemento perimetrale nella tabella di input del nodo di origine. Questo metodo garantisce che il nodo di origine di un bordo esista sempre.
- Crea una limitazione della chiave esterna sugli spigoli per assicurarti che il nodo di destinazione di uno spigolo esista sempre.
L'esempio seguente utilizza l'interleaving e una chiave esterna per applicare integrità referenziale:
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;
Usa ELIMINA CASCATA per rimuovere automaticamente i bordi durante l'eliminazione di un nodo
Se utilizzi gli interfoli o una chiave esterna per impedire i bordi pendenti, utilizza la
ON DELETE
per controllare il comportamento quando vuoi eliminare un nodo con
bordi ancora attaccati. Per ulteriori informazioni, vedi
eliminare a cascata per le tabelle con interleaving
e
elimina a cascata con chiavi esterne.
Puoi utilizzare ON DELETE
nei seguenti modi:
ON DELETE NO ACTION
(o omissione della clausolaON DELETE
): l'eliminazione di un nodo con bordi non andrà a buon fine.ON DELETE CASCADE
: l'eliminazione di un nodo rimuove automaticamente i bordi associati nella stessa transazione.
Eliminazione in cascata per gli archi che collegano tipi diversi di nodi
Elimina gli archi quando viene eliminato il nodo di origine. Ad esempio,
INTERLEAVE IN PARENT Person ON DELETE CASCADE
elimina tutti i bordiPersonOwnAccount
in uscita dal nodoPerson
da eliminare. Per ulteriori informazioni, consulta Creare tabelle con interfoliazione.Elimina i bordi quando viene eliminato il nodo di destinazione. Ad esempio,
CONSTRAINT FK_Account FOREIGN KEY(account_id) REFERENCES Account(id) ON DELETE CASCADE
elimina tutti gli archiPersonOwnAccount
in entrata nel nodoAccount
da eliminare. Per ulteriori informazioni, vedi Chiavi esterne.
Elimina a cascata per i bordi che collegano lo stesso tipo di nodi
Quando i nodi di origine e di destinazione di un perimetro hanno lo stesso tipo
è con interleaving nel nodo di origine, puoi definire ON DELETE CASCADE
solo per il nodo di origine o di destinazione (ma non per entrambi i nodi).
Per rimuovere automaticamente gli spigoli inutilizzati in entrambi i casi, crea una chiave esterna sul riferimento del nodo di origine dell'elemento anziché interlacciare la tabella di input dell'elemento con la tabella di input del nodo di origine.
Consigliamo di interfoliare per
ottimizzare l'attraversamento del bordo in avanti.
Prima di procedere, assicurati di verificare l'impatto sui tuoi carichi di lavoro. Guarda l'esempio seguente, che utilizza AccountTransferAccount
come tabella di input di bordo:
--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);
Filtrare in base alle proprietà dei nodi o degli archi con indici secondari
Gli indici secondari sono essenziali per un'elaborazione efficiente delle query. Supportano la ricerca rapida di nodi ed archi in base a valori di proprietà specifici, senza dover attraversare l'intera struttura del grafo. Questo è importante quando stai lavorando con grafici di grandi dimensioni, perché attraversando tutti i nodi e gli archi può essere molto inefficiente.
Velocizzare il filtro dei nodi per proprietà
Per velocizzare il filtro in base alle proprietà dei nodi, crea indici secondari sulle proprietà. Ad esempio, la seguente query trova gli account per un determinato nickname. Senza un indice secondario, tutti i nodi (Account
) vengono analizzati per trovare una corrispondenza
i criteri di filtro.
GRAPH FinGraph
MATCH (acct:Account)
WHERE acct.nick_name = "abcd"
RETURN acct.id;
Per velocizzare la query, crea un indice secondario per la proprietà filtrata, come показано показано nell'esempio seguente:
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);
Suggerimento:usa indici con filtri NULL per le proprietà sparse. Per ulteriori informazioni, consulta Disattivare l'indicizzazione dei valori NULL.
Accelera l'attraversamento in avanti utilizzando i filtri sulle proprietà degli spigoli
Quando esegui la traversata di un bordo applicando un filtro alle relative proprietà, puoi velocizzare la query creando un indice secondario sulle proprietà del bordo e intercalando l'indice nel nodo di origine.
Ad esempio, la seguente query trova gli account di proprietà di una determinata persona dopo un determinato momento:
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;
Per impostazione predefinita, questa query legge tutti i bordi della persona specificata, quindi filtra
i bordi che soddisfano la condizione in create_time
.
L'esempio seguente mostra come migliorare l'efficienza delle query creando
un indice secondario sul riferimento del nodo di origine perimetrale (id
) e la proprietà perimetrale
(create_time
). Interfoliare l'indice sotto la tabella di input del nodo di origine in
collocare l'indice con il nodo di origine.
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;
Con questo approccio, la query può trovare in modo efficiente tutti gli spigoli che soddisfano la condizione su create_time
.
Accelerare il traversale degli edge in senso inverso con il filtro delle proprietà degli edge
Quando attraversi un bordo inverso mentre ne filtri le proprietà, puoi velocizzare la query creando un indice secondario tramite il nodo di destinazione le proprietà degli angoli per i filtri.
La query di esempio seguente esegue l'attraversamento inverso con il filtro attivo proprietà degli spigoli:
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;
Per velocizzare questa query utilizzando un indice secondario, utilizza una delle seguenti opzioni:
Crea un indice secondario nel riferimento del nodo di destinazione perimetrale (
account_id
) e la proprietà perimetrale (create_time
), come mostrato in nell'esempio seguente: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);
Questo approccio offre prestazioni migliori perché gli archi inversi sono ordinati per
account_id
ecreate_time
, il che consente al motore di query di trovare in modo efficiente gli archi peraccount_id
che soddisfano la condizione sucreate_time
. Tuttavia, se pattern di query diversi filtrano in base a , ogni proprietà potrebbe richiedere un indice separato, che può essere aggiungere overhead.Crea un indice secondario sul riferimento del nodo di destinazione dell'elemento perimetrale (
account_id
) e memorizza la proprietà dell'elemento perimetrale (create_time
) in una colonna di archiviazione, come mostrato nell'esempio seguente: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);
Questo approccio può memorizzare più proprietà, ma la query deve leggere tutti gli archi del nodo di destinazione e poi filtrare in base alle proprietà degli archi.
Puoi combinare questi approcci seguendo queste linee guida:
- Utilizza le proprietà di confine nelle colonne dell'indice se vengono utilizzate nelle query critiche per le prestazioni.
- Per le proprietà utilizzate in query meno sensibili alle prestazioni, aggiungile in le colonne di archiviazione.
Modella i tipi di nodi e archi con etichette e proprietà
I tipi di nodi ed archi vengono comunemente modellati con le etichette. Tuttavia, puoi anche utilizzare le proprietà per i tipi di modelli. Prendiamo ad esempio un caso in cui esistono molti tipi di account diversi, come BankAccount
, InvestmentAccount
e RetirementAccount
. Puoi archiviare gli account in tabelle di input separate e modellizzarli come etichette separate oppure puoi archiviarli in un'unica tabella di input e utilizzare una proprietà per distinguere i tipi.
Inizia il processo di definizione del modello creando i tipi con le etichette. Prendi in considerazione utilizzando le proprietà nei seguenti scenari.
Migliorare la gestione dello schema
Se il grafo contiene molti tipi diversi di nodi ed archi, la gestione di una tabella di input distinta per ciascuno può diventare difficile. Per semplificare la gestione dello schema, il tipo come proprietà.
Tipi di modelli in una proprietà per gestire i tipi che cambiano frequentemente
Quando modelli i tipi come etichette, l'aggiunta o la rimozione dei tipi richiede modifiche a lo schema. Se esegui troppi aggiornamenti dello schema in un breve periodo di tempo, Spanner potrebbe throttle l'elaborazione degli aggiornamenti dello schema in coda. Per ulteriori informazioni, vedi Limita la frequenza degli aggiornamenti dello schema.
Se devi modificare spesso lo schema, ti consigliamo di modellare lo schema digita una proprietà per aggirare le limitazioni di frequenza dello schema aggiornamenti.
Velocizzare le query
I tipi di modellazione con proprietà potrebbero accelerare le query quando il nodo o il pattern perimetrale
fa riferimento a più etichette. La seguente query di esempio trova tutte le istanze
SavingsAccount
e InvestmentAccount
di proprietà di Person
, presuppone che l'account
i tipi sono modellati con etichette:
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:SavingsAccount|InvestmentAccount)
RETURN acct.id;
Il pattern del nodo acct
fa riferimento a due etichette. Se si tratta di un
query critica per le prestazioni, valuta la possibilità di modellare Account
utilizzando una proprietà. Questo
potrebbe fornire prestazioni delle query migliori, come mostrato nell'esempio
esempio. Ti consigliamo di eseguire il benchmark di entrambe le query.
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:Account)
WHERE acct.type IN ("Savings", "Investment")
RETURN acct.id;
Archivia il tipo nella chiave dell'elemento node per velocizzare le query
Per velocizzare le query con filtri in base al tipo di nodo quando un tipo di nodo è modellato con una proprietà e il tipo non cambia durante la vita del nodo, segui questi passaggi:
- Includi la proprietà nella chiave dell'elemento node.
- Aggiungi il tipo di nodo nella tabella di input perimetrale.
- Includi il tipo di nodo nelle chiavi di riferimento all'elemento.
L'esempio seguente applica questa ottimizzazione al nodo Account
e al
Bordo 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
);
Configura il TTL su nodi e perimetrali
La durata (TTL) di Spanner è un meccanismo che supporta la scadenza e la rimozione automatica dei dati dopo un periodo specificato. Questo viene spesso utilizzato per i dati con una durata o pertinenza limitata, come informazioni sulle sessioni, cache temporanee o log degli eventi. In questi casi, il TTL contribuisce a mantenere le dimensioni e le prestazioni del database.
L'esempio seguente utilizza il TTL per eliminare gli account 90 giorni dopo la loro chiusura:
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));
Se la tabella dei nodi ha un TTL e una tabella perimetrale con interleaving al suo interno,
l'interlea deve essere definita con
ON DELETE CASCADE
Analogamente, se la tabella dei nodi ha un TTL e fa riferimento a una tabella perimetrale,
attraverso una chiave esterna, quest'ultima deve essere definita con
ON DELETE CASCADE
.
Nell'esempio seguente, AccountTransferAccount
viene archiviato per un massimo di dieci anni
mentre un account rimane attivo. Quando un account viene eliminato, viene eliminata anche la cronologia dei trasferimenti.
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));
Unisci le tabelle di input dei nodi e degli edge
Puoi utilizzare la stessa tabella di input per definire più di un nodo e un'associazione nello schema.
Nelle seguenti tabelle di esempio, i nodi Account
hanno una chiave composta(owner_id, account_id)
. Esiste una definizione implicita dell'elemento di bordo: il nodo Person
con chiave (id
) possiede il nodo Account
con chiave composita (owner_id, account_id)
quando id
è uguale a 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);
In questo caso, puoi utilizzare la tabella di input Account
per definire il valore Account
e sul perimetro PersonOwnAccount
, come mostrato nell'esempio di schema che segue.
Per garantire che tutti i nomi delle tabelle degli elementi siano univoci, l'esempio fornisce il bordo
definizione della tabella per 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
);
Passaggi successivi
- Crea, aggiorna o elimina uno schema di grafo Spanner.
- Inserisci, aggiorna o elimina i dati di Spanner Graph.