Intermedio9 min di lettura

Come modellare i dati in DynamoDB

In SQL modelli prima entità e relazioni, poi ti fidi che il query planner assembli in seguito qualunque cosa tu chieda. DynamoDB inverte tutto ciò. Modelli le letture che già sai che farai, e le chiavi esistono per servirle.

Non c'è un motore di join né un planner che sceglie una strategia a runtime. Una Query legge una sola partizione lungo una sola chiave, e questo è l'intero contratto di prestazione. Quindi progetti le chiavi per pattern di accesso noti, non per uno schema ordinato.

AWS lo dice chiaramente nella sua guida alle best practice: "non dovresti iniziare a progettare lo schema finché non conosci le domande a cui dovrà rispondere".

Questa guida percorre l'intero processo su un dominio: una leaderboard di un gioco multiplayer che traccia i giocatori, le partite che giocano e il loro ranking per stagione. Andiamo da una lista di domande a uno schema di chiavi funzionante.

Come si modellano i dati in DynamoDB?

Modella prima le letture, non le tabelle. Elenca ogni query che l'app fa, poi progetta una e una così che ogni domanda si risolva in una singola Query o GetItem. Colloca insieme gli item che vengono letti insieme, spazia sui valori nella chiave di ordinamento, e aggiungi un GSI per ogni pattern di accesso che la tabella di base non può servire.

  • Elenca prima le letture, non le tabelle. Le domande sono la specifica; i nomi sono una distrazione.
  • Ogni domanda deve essere una Query o una GetItem. Se una domanda richiede uno Scan, il modello è sbagliato.
  • Gli item collocati insieme condividono una ; qualunque cosa su cui spazi va nella .
  • Una domanda a cui la tabella di base non può rispondere ottiene un — mai uno Scan con un filtro.

Passo 1 — Inquadra il problema come domande, non tabelle

Resisti all'impulso di disegnare le tabelle players, matches e scores. Quell'istinto è l'abitudine SQL, e qui è sbagliato. Scrivi invece ogni lettura che l'app compie davvero. Per la nostra leaderboard:

  • Recupera il profilo di un giocatore per id.
  • Elenca le partite recenti di un giocatore, dalla più nuova.
  • Mostra i top N giocatori per una data stagione, classificati per rating.
  • Cerca un giocatore per il suo handle pubblico (es. per un URL di profilo).

Queste quattro domande — non i nomi — sono la specifica. Ciascuna deve risolversi in una singola Query (o GetItem), perché è l'unica forma di accesso che DynamoDB serve a basso costo su larga scala.

Se una domanda può ricevere risposta solo scansionando la tabella, il modello è sbagliato, e lo sentirai in latenza e costo — vedi Query vs Scan per capire perché uno Scan è la mina da evitare.

L'intero metodo è una pipeline breve e ordinata che esegui una volta per dominio:

NoNoElenca le entitàEnumera i pattern di accessoProgetta PK / SKper servirliOgni letturauna sola Query?Aggiungi un GSIper ogni lettura residuaValida sudati realiEmerge unanuova domanda?Rilascia il modello

Ogni passo qui sotto mappa su un riquadro: elenca, enumera, progetta le chiavi, aggiungi indici per il resto, poi valida.

Passo 2 — Comprendi le primitive con cui stai modellando

Una tabella ha una chiave di partizione (PK) che sceglie su quale partizione fisica vive un item, e una chiave di ordinamento (SK) opzionale che ordina gli item all'interno di quella partizione.

La documentazione sui componenti fondamentali di AWS chiama la coppia la chiave primaria dell'item. Una Query mira sempre a esattamente un valore di PK e può fare range-scan o filtrare la SK — è questo l'intero armamentario.

Questo design a singola partizione è ciò che permette a DynamoDB di offrire le letture prevedibili, a bassa latenza e partizionate orizzontalmente descritte per la prima volta nel paper Amazon Dynamo del 2007.

Due conseguenze guidano ogni decisione qui sotto:

  1. Gli item che vengono letti insieme dovrebbero condividere una chiave di partizione così che una sola Query li restituisca in una singola richiesta fatturata.
  2. Qualunque cosa su cui vuoi spaziare (partite recenti, rating migliori) deve vivere nella chiave di ordinamento, perché è l'unico attributo che una Query può ordinare e delimitare.

Quando una domanda richiede una forma di accesso diversa da quella che la tabella di base fornisce, aggiungi un Global Secondary Index — una ri-proiezione della tabella sotto una PK/SK diversa.

(Per GSI contro Local Secondary Index, vedi GSI vs LSI.)

Passo 3 — Progetta le chiavi, una domanda alla volta

Usiamo una singola tabella con attributi chiave generici e sovraccarichi — l'approccio single-table — perché un giocatore e le sue partite vengono letti insieme.

Inventa i tuoi prefissi; qui PLAYER#, MATCH# e SEASON# etichettano il tipo di entità dentro chiavi altrimenti generiche.

Le domande 1 e 2 (profilo + partite recenti) condividono una partizione, quindi entrambe si agganciano alla stessa PK:

partitionIdrangeIdattributes
PLAYER#u8231PROFILEhandle, region, createdAt
PLAYER#u8231MATCH#2026-06-23T14result=win, ratingDelta=+18, mapId
PLAYER#u8231MATCH#2026-06-23T11result=loss, ratingDelta=-15, mapId

Query partitionId = "PLAYER#u8231" restituisce il profilo e ogni partita in una sola lettura. Per il solo profilo, GetItem.

Per le partite recenti, rangeId begins_with "MATCH#" con ScanIndexForward = false le percorre dalla più nuova — il timestamp nella chiave di ordinamento fa l'ordinamento gratis.

Le domande 3 e 4 non possono ricevere risposta da quella partizione — pivotano sul rank di stagione e sull'handle, nessuno dei quali è la PK di base. Ciascuna ottiene un GSI.

Aggiungiamo due coppie di attributi indice generici — seasonPartition / seasonSort per l'indice di rank e handlePartition / handleSort per l'indice di handle — popolati sullo stesso item profilo (quello scritto nel Passo 3, ora mostrato con i suoi attributi indice compilati):

partitionIdrangeIdseasonPartitionseasonSorthandlePartitionhandleSort
PLAYER#u8231PROFILESEASON#2026-Q2RATING#1842HANDLE#nighthawkPLAYER#u8231

Ora Query sull'indice di stagione WHERE seasonPartition = "SEASON#2026-Q2" con ScanIndexForward = false restituisce i giocatori classificati per rating — questa è la leaderboard.

Un secondo indice con chiave handlePartition = "HANDLE#…" risolve un handle pubblico in un id di giocatore in una sola lettura. Una sola tabella fisica, quattro pattern di accesso da singola Query.

Una nota di su RATING#1842: DynamoDB ordina le chiavi di ordinamento lessicograficamente, non numericamente, quindi un rating deve essere zero-paddato a una larghezza fissa (RATING#01842) o 9 ordinerebbe dopo 1000. È un classico tranello di modellazione che vale la pena azzeccare fin da subito.

Passo 4 — Valida il modello in DynoTable

Uno schema di chiavi guadagna fiducia solo quando guardi una vera Query restituire esattamente gli item che ti aspettavi e nulla di più.

Apri la tabella in DynoTable, esegui la query della leaderboard contro l'indice di stagione, e conferma che la partizione torni classificata e delimitata — nessuno Scan, nessun ordinamento lato client.

Esecuzione della Query della leaderboard di stagione contro il GSI in DynoTable e ispezione del risultato classificato.
Esecuzione della Query della leaderboard di stagione contro il GSI in DynoTable e ispezione del risultato classificato.

Quando costruisci le condition expression per queste query — il begins_with, il seasonPartition = :p, il binding del placeholder :p — lascialo fare al DynamoDB Expression Builder.

Genera la KeyConditionExpression, gli ExpressionAttributeNames e gli ExpressionAttributeValues, così una parola riservata come result o un placeholder con un refuso non rompe mai silenziosamente una lettura.

Passo 5 — Insidie e prossimi passi

Qualche trappola da controllare prima di mettere in produzione il modello:

  • Non modellare relazioni che non leggi mai insieme. Un GSI per domanda è economico; un GSI sprecato è un costo ricorrente. Aggiungi indici dalla lista delle domande, non in modo speculativo.
  • Sorveglia il calore delle partizioni. Se una PK (un giocatore celebrità, una singola stagione calda) assorbe la maggior parte del traffico, quella partizione può andare in throttling. Distribuisci le scritture con uno shard a suffisso quando una chiave è comprovatamente calda — AWS lo tratta sotto partition-key design.
  • Zero-padda e ISO-8601 tutto ciò che è numerico o temporale in una chiave di ordinamento, così che l'ordinamento lessicografico corrisponda all'ordine che intendi.
  • Una nuova domanda = una nuova chiave o indice, mai uno Scan. Quando un pattern di accesso genuinamente nuovo compare in seguito, estendi le chiavi; non tamponarlo con un filtro.

Modella prima le domande, progetta le chiavi così che ciascuna sia una Query, poi dimostralo.

Per un vantaggio di partenza sul passo intermedio, lo strumento gratuito di Single-Table Design trasforma una lista di pattern di accesso come questa in un piano PK/SK/GSI, con Item di esempio e stime dei costi.

Prova DynoTable per sfogliare la tua tabella, eseguire queste query contro la tabella di base e i GSI fianco a fianco, e guardare i pattern di accesso che hai progettato restituire esattamente ciò che avevi pianificato. E per la domanda che non hai modellato, il suo SQL Workbench esegue veri JOIN, GROUP BY e aggregazioni lato client.

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