Principiante6 min di lettura

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 Query di restituire un range (>=, between, begins_with) invece di un solo Item, senza Scan.
  • 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 sempliceComposite key
AttributiSolo chiave di partizioneChiave di partizione + sort key
UnicitàValore chiave di partizioneLa coppia di valori
Più Item per partizioneNo
Query di un rangeNo (solo GetItem)Sì (begins_with, between, >)
Adatta naturalmente aLookup per idSerie 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:

deviceIdreadingTstempChumidity
DEV#a1b22026-06-23T08:00:00Z21.448
DEV#a1b22026-06-23T08:05:00Z21.747
DEV#a1b22026-06-23T08:10:00Z22.146
DEV#c9d82026-06-23T08:00:00Z19.855

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:

Partizione: DEV#a1b2readingTs 08:00readingTs 08:05readingTs 08:10Query deviceId = DEV#a1b2

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:00Z ti permette di mischiare tipi di entità sotto una partizione e affettarli con begins_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.

Aggiornato