Composite Primary Key in DynamoDB
Una composite primary key sono due attributi: una chiave di partizione e una sort key. La chiave di partizione decide dove vive un Item; la sort key ordina gli Item all'interno di quella partizione.
Venendo da SQL, pensala meno come una colonna id univoca e più come
GROUP BY partition, ORDER BY sort incorporato nella tabella stessa.
Cos'è una composite primary key in DynamoDB?
Una composite primary key in DynamoDB combina due attributi: una chiave di partizione e una sort key. La chiave di partizione decide in quale partizione fisica vive un Item; la sort key ordina gli Item all'interno di quella partizione. Insieme formano l'identità univoca dell'Item e permettono a una singola Query di restituire un range ordinato invece di un solo Item.
- Due parti, due compiti. La chiave di partizione instrada l'Item a una partizione fisica; la sort key ordina ogni Item che condivide quella chiave di partizione.
- L'unicità è la coppia. Due Item possono condividere un valore di chiave di partizione purché le loro sort key differiscano — è così che una partizione contiene molte righe.
- La sort key è tutto il punto. È ciò che permette a una
Querydi restituire un range (>=,between,begins_with) invece di un solo Item, senzaScan. - Le chiavi devono essere scalari. Chiave di partizione e sort key possono essere solo string, number o binary — niente map, niente list (AWS docs).
Chiave semplice vs composite key
Una simple primary key è solo una chiave di partizione. Identifica univocamente un
Item, e lo rileggi con GetItem. Tutto qui — niente letture di range, niente
"dammi gli N più recenti".
Una composite key aggiunge la sort key, e quella singola aggiunta è ciò che fa sentire DynamoDB come un database invece di una hash map.
| Chiave semplice | Composite key | |
|---|---|---|
| Attributi | Solo chiave di partizione | Chiave di partizione + sort key |
| Unicità | Valore chiave di partizione | La coppia di valori |
| Più Item per partizione | No | Sì |
Query di un range | No (solo GetItem) | Sì (begins_with, between, >) |
| Adatta naturalmente a | Lookup per id | Serie temporali, uno-a-molti, cronologia |
Modella una tabella di letture sensore
Diciamo che raccogli campioni di temperatura da una flotta di sensori sul campo. Il pattern di accesso è "ottieni le letture per un device, più recenti prima, in una finestra temporale". È una composite key da manuale.
Usa l'id del device come chiave di partizione e il timestamp della lettura come sort key:
| deviceId | readingTs | tempC | humidity |
|---|---|---|---|
| DEV#a1b2 | 2026-06-23T08:00:00Z | 21.4 | 48 |
| DEV#a1b2 | 2026-06-23T08:05:00Z | 21.7 | 47 |
| DEV#a1b2 | 2026-06-23T08:10:00Z | 22.1 | 46 |
| DEV#c9d8 | 2026-06-23T08:00:00Z | 19.8 | 55 |
Tutte e tre le letture DEV#a1b2 finiscono nella stessa partizione, fisicamente memorizzate
insieme e ordinate per readingTs.
AWS chiama la chiave di partizione l'hash attribute e la sort key il range attribute — la sort key è un range entro cui puoi fare lo scan (AWS docs).
Ecco come gli Item collassano in un'unica item collection sotto ogni chiave di partizione:
Una sola Query sulla chiave di partizione legge ogni lettura per quel device,
già in ordine di timestamp — niente ordinamento sul client, nessun secondo round trip.
Interroga il range, non fare lo scan
Poiché readingTs è una stringa ISO-8601, si ordina lessicograficamente nello stesso
modo in cui si ordina cronologicamente. Quindi una lettura per finestra temporale è un range di key-condition,
non un filtro:
Query
deviceId = "DEV#a1b2"
readingTs BETWEEN "2026-06-23T08:00:00Z" AND "2026-06-23T08:10:00Z"
Questa è una KeyConditionExpression — restringe la lettura prima che DynamoDB
restituisca i dati, quindi paghi solo per gli Item nella finestra. Una FilterExpression
gira dopo la lettura e ti fattura tutto ciò che ha scansionato; è quello
il footgun dello Scan in miniatura.
L'espressione stessa, con placeholder e valori tipizzati, è fastidiosa da scrivere
a mano. Costruiscila visivamente con il
DynamoDB Expression Builder e copia la
KeyConditionExpression esatta nella tua chiamata SDK.
Progetta la sort key di proposito
La sort key non è metadato gratuito — è l'unica leva per le letture di range, quindi modellala sulle tue query.
- Usa un timestamp ordinabile. Stringhe ISO-8601 o numeri epoch zero-paddati si ordinano correttamente; le date localizzate grezze no.
- Mettile un prefisso per l'overloading uno-a-molti. Una sort key come
READING#2026-06-23T08:00:00Zti permette di mischiare tipi di entità sotto una partizione e affettarli conbegins_with. È la cucitura verso il single-table design. - Metti la dimensione ad alta cardinalità nella chiave di partizione. L'id del sensore ha
migliaia di valori, quindi distribuisce uniformemente le scritture. Una chiave di partizione a bassa
cardinalità (diciamo
region) crea una hot partition.
Quando una composite key ti morde
È un impegno, non una comodità. La trappola: scegli una chiave di partizione, fai il deploy, poi scopri un pattern di accesso che richiede un raggruppamento diverso — "tutte le letture sopra i 30°C su tutta la flotta".
La tabella base non può rispondere; la chiave di partizione è fissa. Le tue opzioni sono un global secondary index con una chiave diversa, oppure ristrutturare.
Enumera le tue letture prima di impegnare lo schema di chiave. Cambiare una primary key
significa una migrazione di tabella, non un ALTER TABLE.
Prossimi passi
Le composite key sono la fondazione sotto le item collection, le relazioni uno-a-molti e la maggior parte dei design di indice utili — leggi single-table design e GSI vs LSI come prossimo passo per vedere dove portano.
Abbozza la tua KeyConditionExpression nel
DynamoDB Expression Builder, poi
prova DynoTable per navigare le tue partizioni reali e osservare l'ordine
di sort allinearsi sulle tue tabelle.