Quando NON Usare il Single-Table Design in DynamoDB
Il single-table design è il consiglio di default per DynamoDB, e se lo merita: una
Query restituisce un genitore e i suoi figli, niente join, niente N+1.
Ma è uno scambio — compri velocità di lettura con uno schema rigido e opaco. Alcuni carichi di lavoro non possono permettersi quel prezzo, e forzare una tabella su di essi è un footgun a sé.
Quando non dovresti usare il single-table design in DynamoDB?
Evita il single-table design quando il tuo carico di lavoro è incentrato su analytics OLAP pesanti, CRUD semplice su un pugno di entità non correlate, o entità che scalano e falliscono in modo indipendente. In questi casi più tabelle si leggono meglio, costano uguale e restano flessibili. Il single-table design vince solo quando i pattern di accesso sono noti, correlati e ad alto volume.
- Analytics pesanti? Non fare single-table. Le chiavi sovraccaricate sono ostili all'OLAP — esporta in uno store colonnare e interroga lì.
- CRUD semplice con una manciata di pattern di accesso? Una tabella per entità va bene, è leggibile, e non ti costa nulla in performance.
- Entità che scalano o falliscono indipendentemente? Tabelle separate ti permettono di tunare, fatturare e isolare il raggio d'esplosione per ognuna.
- Il single-table vince ancora quando i tuoi pattern sono noti, correlati e ad alto volume — è il caso per cui è stato costruito.
Sappi cosa costa davvero il single-table
Il single-table design non è gratis; sposta solo il costo fuori dal percorso di lettura e su tutto il resto. Paghi in leggibilità e flessibilità.
Una tabella che contiene cinque tipi di entità dietro PK/SK è difficile da leggere, difficile da
fare onboarding, e difficile da cambiare. Un nuovo pattern di accesso può significare un backfill
su ogni tipo di Item nella partizione.
Quindi la domanda non è "il single-table è buono?". È "i miei pattern di accesso giustificano la rigidità?". Quando non lo fanno, reggiungi a più tabelle.
Non fare single-table su un carico di lavoro analytics
DynamoDB è costruito per OLTP — letture piccole, note, point-and-range. Le analytics sono
OLAP: GROUP BY, grandi aggregati, slicing ad-hoc su tutto il dataset. Le
due tirano in direzioni opposte.
Il single-table design peggiora l'OLAP, non lo migliora. Chiavi sovraccaricate e tipi di entità misti significano che un job di analytics deve prima districare quale Item è quale prima di poter sommare qualcosa — l'opposto di una scan colonnare pulita.
Venendo da SQL, il riflesso è scrivere l'aggregato sulla tabella live.
In DynamoDB quello è uno Scan completo — paghi e leggi ogni Item, che è il
footgun dello Scan a pieno volume.
La soluzione non è una chiave più ingegnosa. È uno store diverso. L'indicazione di AWS stessa è esportare DynamoDB su S3 ed eseguire le analytics con un query engine come Athena.
Tieni OLTP e OLAP su engine separati (AWS DynamoDB Developer Guide,
S3DataExport.html).
Non fare single-table su CRUD semplice
Se la tua app legge e scrive poche entità non correlate per il loro id, e hai forse tre pattern di accesso, il single-table non ti compra nulla.
Prendi una tabella Tenants e una tabella ApiKeys per un piccolo tool B2B:
| TenantId | Name | PlanTier |
|---|---|---|
| TNT-8842 | Northwind | pro |
| KeyId | TenantId | Scope |
|---|---|---|
| KEY-01H9... | TNT-8842 | read-write |
Ogni query è un GetItem per id, o una Query su un GSI con chiave su TenantId.
Non c'è alcun fetch genitore-e-figli da ottimizzare, quindi non c'è nulla che una
partizione sovraccaricata possa vincere. Due tabelle chiare si leggono meglio di una torbida.
La trappola è il cargo-culting del single-table perché è "best practice". La best practice è access-pattern-first. Se i pattern sono banali, la forma semplice è la forma giusta.
Dividi le tabelle che scalano o falliscono indipendentemente
Una singola tabella condivide una superficie di throughput, un backup, un raggio d'esplosione. Quando due entità hanno tassi di scrittura o esigenze di durabilità molto diversi, quel destino condiviso diventa una passività.
Immagina un sistema di tracciamento flotta. I veicoli cambiano raramente; la loro telemetria si riversa ogni secondo:
| VehicleId | Make | Model | Region |
|---|---|---|---|
| VEH-204 | Volvo | FH16 | eu-west |
| DeviceTs | VehicleId | SpeedKph | Fuel |
|---|---|---|---|
| 2026-06-23T10:00:01Z | VEH-204 | 88 | 0.61 |
Due tabelle ti permettono di provisionare la telemetria per un firehose, tenere i veicoli piccoli e economici, impostare un TTL solo sulla telemetria, e impedire a una tempesta di scritture di telemetria di mettere in throttling le letture del catalogo veicoli. Una sola tabella accoppia tutto questo.
Secondo il paper Amazon Dynamo del 2007, partizionamento e disponibilità sono preoccupazioni di prima classe — tabelle indipendenti ti danno controllo indipendente su entrambi.
Mappa la decisione prima di impegnarti
Fai passare il carico di lavoro attraverso un gate: le entità sono correlate, e i pattern sono noti e ad alto volume? Se no, più tabelle.
Ecco la scelta come flusso — parti dall'alto e segui il primo ramo che corrisponde:
Solo la foglia in basso a destra merita il single-table; ogni altro percorso è servito meglio da più di una tabella.
Singola vs multiple, testa a testa
| Fattore | Single-table | Tabelle multiple |
|---|---|---|
| Letture correlate | Una Query, niente join | Join client-side o round-trip extra |
| Leggibilità | Chiavi sovraccaricate opache | Una entità per tabella, auto-documentante |
| Nuovo pattern di accesso | Spesso un backfill | Aggiungi una tabella o un GSI in isolamento |
| Analytics / OLAP | Ostile — districa prima di aggregare | Esporti comunque, ma più pulito per entità |
| Scaling indipendente | Throughput + raggio d'esplosione condivisi | Tuna, fattura, TTL e fai backup separatamente |
| Migliore quando | Pattern noti, correlati, ad alto volume | Non correlati, in evoluzione o analitici |
Errori + prossimi passi
L'errore speculare è la sovra-correzione — dividere entità genuinamente correlate e ad alto volume in una tabella-per-entità e ricostruire join in stile SQL nella tua app. È la trappola N+1 che il single-table elimina.
Scegli la forma che i pattern di accesso chiedono, non il dogma.
Quando modelli relazioni, appoggiati al tipo di indice giusto — vedi GSI vs LSI prima di aggiungerne uno.
Quando scrivi una query su uno schema multi-tabella, abbozza la
KeyConditionExpression prima nel
DynamoDB Expression Builder.
Così cogli una forma a Scan completo prima che arrivi in produzione.
Poi prova DynoTable per navigare entrambe le forme sulle tue tabelle e vedere quale i tuoi pattern di accesso vogliono davvero.