Intermedio8 min di lettura

Relazioni molti-a-molti in DynamoDB

Uno studente si iscrive a molti corsi; un corso può contenere molti studenti. In SQL raggiungi per una tabella di join e un "JOIN" a tre tabelle.

DynamoDB non ha join, quindi la relazione deve vivere nelle chiavi — e il il trucco è memorizzare ciascun fronte di registrazione in una forma in cui entrambe le parti possano Query direttamente.

Questa guida accompagna gli studenti ↔ al problema dei corsi dall'inizio alla fine: i modelli di accesso, il

pattern che li risolve, uno schema chiave originale che puoi copiare e come leggere entrambe le direzioni senza mai scansionare la tabella.

Come si modella una relazione molti-a-molti in DynamoDB?

DynamoDB non ha join, quindi modelli una relazione molti-a-molti conmodello: memorizza ogni collegamento come un proprio elemento di bordo con chiave da un lato, quindi aggiungi un GSI invertito che scambia le chiavi. Un singolo bordo, scritto una volta, risponde quindi alle domande da entrambe le direzioni in modo economico.

  • Memorizza ogni registrazione come elemento marginale, non come attributo di elenco su entrambi i lati.
  • Inserisci il bordo dello studente (PK = STU#…, SK = ENROLL#CRS#…) quindi uno Query restituisce l'intero elenco dei corsi di uno studente.
  • Aggiungi un invertito che scambia i ruoli (GSI1PK = CRS#…) quindi lo stesso bordo risponde anche "chi c'è in questo corso?".
  • Un bordo, scritto una volta, si legge in modo economico in entrambe le direzioni: questo è l'intero gioco.

Inquadra prima i modelli di accesso

La modellazione DynamoDB è basata innanzitutto sul modello di accesso: sei tu a decidere le letture prima di scegliere un nome dell'attributo singolo. Una relazione molti-a-molti ha quasi sempre due simmetrici legge più le ricerche di entità:

  • Ottieni il profilo di uno studente ed elenca tutti i corsi a cui è iscritto.
  • Ottieni i metadati di un corso e elenca tutti gli studenti iscritti a quel corso.
  • Cerca un singolo vantaggio di iscrizione: per aggiornare un voto o abbandonare il corso.

Le due letture dell'elenco puntano in direzioni opposte attraverso lo stesso insieme di bordi. Un design ingenuo serve uno a buon mercato e forza un Scan per l'altro: l'esatto fucile coperto in Query vs Scan.

Il compito è rendere entrambe le direzioni un singolo Query.

Utilizza il modello elenco di adiacenze

La guida di DynamoDB per le relazioni è la lista di adiacenze: modella ciascuna relazione come un elemento la cui chiave di partizione è un endpoint e la cui chiave di ordinamento è il altro.

AWS lo documenta sul Best practice per la gestione delle relazioni molti-a-molti pagina della Guida per sviluppatori DynamoDB.

Perché le chiavi e non un secondo tabella? Perché la primitiva che ti dà DynamoDB è un Query contro una singola partizione.

Un Query legge un intervallo contiguo di valori di chiavi di ordinamento sotto una chiave di partizione in uno operazione fatturata: questo è l'unico "join" offerto dal motore.

Per ottenere una relazione che si legga in modo semplice da entrambi i lati, duplichi il bordo: scriverlo una volta digitato dallo studente, quindi utilizzare un indice secondario per proiettare lo stesso bordo incentrato sul corso.

Questo è il pensiero in chiave sovraccarica da Progettazione a tabella singola, applicato invece a una relazione di una gerarchia genitore-figlio.

La forma è rappresentata da due viste impilate dello stesso bordo: la tabella di base impostata dallo studente, il invertito GSI digitato per corso:

stesso vantaggio, chiaviscambiatestesso vantaggio, chiaviscambiateInverted GSI1 keyed by courseGSI1PK CRS#math204GSI1SK STU#a91GSI1PK CRS#cs101GSI1SK STU#a91Tabella base chiave per studentePK STU#a91SK ENROLL#CRS#math204PK STU#a91SK ENROLL#CRS#cs101

Ogni bordo viene scritto una volta sulla tavola base e proiettato nel GSI con le sue chiavi scambiato, quindi un Query contro una delle partizioni legge la relazione in modo economico.

Il lignaggio risale all'Amazzonia del 2007 Documento Dynamo: la chiave di partizione è l'unità di distribuzione e l'accesso con chiave singola è il percorso rapido.

Le relazioni in DynamoDB sono un esercizio per piegare le letture molti-a-molti in modo così veloce percorso.

Fai l'esempio: studenti ↔ corsi

Utilizza una tabella con chiavi generiche, PK e SK, e codifica il tipo di entità nel valore. Il bordo di registrazione ne è il cuore:

PKSKattributes
STU#a91PROFILEname, year, major
STU#a91ENROLL#CRS#math204 enrolledOn, grade
STU#a91ENROLL#CRS#cs101enrolledOn, grade
CRS#math204METADATAtitle, credits, term
CRS#cs101METADATAtitle, credits, term

Un singolo Query PK = "STU#a91" restituisce il profilo dello studente e ogni iscrizione in una lettura. Restringilo con SK begins_with "ENROLL#" per ottenere solo i bordi del percorso. Questo risolve "elencare i corsi di uno studente".

Ma "elenca gli studenti di un corso" punta nella direzione opposta e la tabella di base non può rispondere it, perché l'ID studente è nella chiave di partizione, non nella chiave di ordinamento.

Aggiungi un indice secondario globale invertito che scambia i ruoli. Dai agli elementi bordo a coppia generica GSI1PK/GSI1SK che tiene il corso dal lato partizione e lo studente dal lato dell'ordinamento:

PKSKGSI1PKGSI1SK
STU#a91ENROLL#CRS#math204CRS#math204STU#a91
STU#b30ENROLL#CRS#math204CRS#math204STU#b30
STU#a91ENROLL#CRS#cs101CRS#cs101STU#a91

Ora Query GSI1 WHERE GSI1PK = "CRS#math204" elenca tutti gli studenti di quel corso: il leggere la tabella di base non potrebbe servire. Un elemento limite, scritto una volta, risponde a entrambi direzioni.

Deve essere un GSI, non un LSI: la partizione del percorso è completamente diversa da quella partizione studente e un LSI condivide la chiave di partizione della tabella di base.

L'indice si estende su più partizioni, quindi deve essere globale: vedi GSI vs LSI.

GSI in DynamoDB vengono popolati in modo asincrono. Una nuova registrazione può richiedere a momento in modo che appaia nella direzione CRS#….

Trattare l'elenco dei corsi letto come- che la Guida per gli sviluppatori chiama esplicitamente per gli indici secondari globali.

Scrivilo e leggilo in DynoTable

Scrivere la registrazione significa impostare quattro attributi chiave più i dati propri dell'edge. Il La condizione che impedisce ad uno studente di iscriversi due volte allo stesso corso è una attribute_not_exists(PK) protegge la chiave composita.

Questo è esattamente il tipo di condizione che puoi assemblare visivamente con DynamoDB Expression Builder invece di scrivendo a mano "ExpressionAttributeNames" e i valori segnaposto.

In DynoTable punti un Query su GSI1, imposta GSI1PK = "CRS#math204" e il roster ritorna come una tabella che puoi leggere, ordinare e modificare sul posto, in entrambe le direzioni la relazione esplorabile da uno schema.

Query inserendo il GSI invertito in DynoTable per elencare tutti gli studenti iscritti a un corso.
Query inserendo il GSI invertito in DynoTable per elencare tutti gli studenti iscritti a un corso.

Insidie e passaggi successivi

  • Non memorizzare un lato come attributo di elenco. Un array courseIds sull'elemento studente sembra ordinato finché un corso non ha bisogno del suo elenco, l'array raggiunge il limite massimo di 400 KB o due iscrizioni gareggiano e si scontrano a vicenda. Gli elementi Edge discreti vengono ridimensionati e aggiornati in modo indipendente.
  • Mantieni i dati edge sull'edge. Il "grado" e l'"enrolledOn" dell'iscrizione appartengono a l'elemento bordo, non duplicato sullo studente o sul corso: c'è esattamente una riga per (studente, corso) coppia da aggiornare.
  • Propagazione Mind GSI. La direzione dell'indice invertito è eventualmente coerente, quindi a letto immediatamente dopo la registrazione potrebbe subire un ritardo di una frazione di secondo.
  • Proietta solo ciò di cui ha bisogno il roster. Una proiezione KEYS_ONLY o ristretta mantiene GSI piccolo quando la visualizzazione dell'elenco necessita solo di ID.

Per approfondire i modelli circostanti, leggi Design a tabella singola per chiavi sovraccaricate e GSI vs LSI per quando l'indice invertito deve essere globale. E a partire dalle proprie relazioni, quelle libere Strumento di progettazione a tabella singola trasforma un elenco dei modelli di accesso come "elenca i corsi di uno studente / elenca gli studenti di un corso" in un piano PK/SK/GSI con elementi di esempio.

Quindi scarica DynoTable per modellare realmente lo schema degli studenti ↔ dei corsi — scrivi i bordi, costruisci la condizione con Expression Builder ed interroga entrambi direzioni della relazione senza una sola scansione. E quando vuoi il comunque la classica visualizzazione JOIN a tre tabelle, SQL di DynoTable Workbench lo esegue sui tuoi tabelle live.

Aggiornato

Prova questo design in modo interattivo

Abbozza le tue entità e i tuoi pattern di accesso nello strumento gratuito di single-table design per DynamoDB — suggerisce template di chiavi PK/SK, mostra un'anteprima delle collezioni di item e indica quali pattern hanno bisogno di un GSI.

Apri lo strumento di single-table design