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
Queryo unaGetItem. Se una domanda richiede unoScan, 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
Scancon 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:
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:
- Gli item che vengono letti insieme dovrebbero condividere una chiave di partizione così che una sola
Queryli restituisca in una singola richiesta fatturata. - Qualunque cosa su cui vuoi spaziare (partite recenti, rating migliori) deve vivere nella chiave di ordinamento, perché è l'unico attributo che una
Querypuò 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:
| partitionId | rangeId | attributes |
|---|---|---|
| PLAYER#u8231 | PROFILE | handle, region, createdAt |
| PLAYER#u8231 | MATCH#2026-06-23T14 | result=win, ratingDelta=+18, mapId |
| PLAYER#u8231 | MATCH#2026-06-23T11 | result=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):
| partitionId | rangeId | seasonPartition | seasonSort | handlePartition | handleSort |
|---|---|---|---|---|---|
| PLAYER#u8231 | PROFILE | SEASON#2026-Q2 | RATING#1842 | HANDLE#nighthawk | PLAYER#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) o9ordinerebbe dopo1000. È 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.

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.


