Iniciante6 min de leitura

Chave Primária Composta no DynamoDB

Uma chave primária composta são dois atributos: uma chave de partição e uma chave de classificação. A chave de partição decide onde um item vive; a chave de classificação ordena os itens dentro daquela partição.

Vindo do SQL, pense nela menos como uma coluna id única e mais como GROUP BY partition, ORDER BY sort embutido na própria tabela.

O que é uma chave primária composta no DynamoDB?

Uma chave primária composta no DynamoDB combina dois atributos: uma chave de partição e uma chave de classificação. A chave de partição decide em qual partição física um item reside; a chave de classificação ordena os itens dentro daquela partição. Juntas, elas formam a identidade única do item e permitem que um único Query retorne um intervalo ordenado em vez de um único item.

  • Duas partes, dois trabalhos. A chave de partição roteia o item para uma partição física; a chave de classificação ordena todo item que compartilha aquela chave de partição.
  • A unicidade é o par. Dois itens podem compartilhar um valor de chave de partição desde que suas chaves de classificação difiram — é assim que uma partição contém muitas linhas.
  • A chave de classificação é o objetivo todo. É o que deixa um Query retornar um intervalo (>=, between, begins_with) em vez de um item, sem Scan.
  • Chaves precisam ser escalares. Chaves de partição e classificação só podem ser string, número ou binário — sem mapas, sem listas (documentação AWS).

Chave simples vs chave composta

Uma chave primária simples é só uma chave de partição. Ela identifica unicamente um item, e você a lê de volta com GetItem. É isso — sem leituras de intervalo, sem "me dê os N mais novos".

Uma chave composta adiciona a chave de classificação, e essa única adição é o que faz o DynamoDB parecer um banco de dados em vez de um hash map.

Chave simplesChave composta
AtributosApenas chave de partiçãoChave de partição + chave de classificação
UnicidadeValor da chave de partiçãoO par de valores
Múltiplos itens por partiçãoNãoSim
Query de um intervaloNão (só GetItem)Sim (begins_with, between, >)
Encaixe naturalBusca por idSérie temporal, um-para-muitos, histórico

Modele uma tabela de leituras de sensores

Digamos que você colete amostras de temperatura de uma frota de sensores de campo. O padrão de acesso é "pegue as leituras de um dispositivo, mais novas primeiro, dentro de uma janela de tempo". Isso é uma chave composta de manual.

Use o id do dispositivo como chave de partição e o timestamp da leitura como chave de classificação:

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

Todas as três leituras de DEV#a1b2 caem na mesma partição, fisicamente armazenadas juntas e ordenadas por readingTs.

A AWS chama a chave de partição de atributo de hash e a chave de classificação de atributo de intervalo — a chave de classificação é um intervalo dentro do qual você pode varrer (documentação AWS).

Eis como os itens colapsam em uma coleção de itens sob cada chave de partição:

Partição: DEV#a1b2readingTs 08:00readingTs 08:05readingTs 08:10Query deviceId = DEV#a1b2

Um Query contra a chave de partição lê toda leitura daquele dispositivo, já em ordem de timestamp — sem ordenação no cliente, sem segunda ida e volta.

Consulte o intervalo, não faça scan nele

Como readingTs é uma string ISO-8601, ela ordena lexicograficamente do mesmo jeito que ordena cronologicamente. Então uma leitura de janela de tempo é um intervalo de condição de chave, não um filtro:

Query
deviceId  = "DEV#a1b2"
readingTs BETWEEN "2026-06-23T08:00:00Z" AND "2026-06-23T08:10:00Z"

Essa é uma KeyConditionExpression — ela estreita a leitura antes de o DynamoDB retornar dados, então você paga apenas pelos itens da janela. Uma FilterExpression roda depois da leitura e te cobra por tudo que ela varreu; essa é a cilada do Scan em miniatura.

A expressão em si, com placeholders e valores tipados, é chata de escrever à mão. Monte-a visualmente com o DynamoDB Expression Builder e copie a KeyConditionExpression exata para a sua chamada de SDK.

Projete a chave de classificação de propósito

A chave de classificação não é metadado grátis — é a única alavanca para leituras de intervalo, então molde-a às suas consultas.

  • Use um timestamp ordenável. Strings ISO-8601 ou números epoch com zero-padding ordenam corretamente; datas localizadas cruas não.
  • Prefixe-a para sobrecarga um-para-muitos. Uma chave de classificação como READING#2026-06-23T08:00:00Z deixa você misturar tipos de entidade sob uma partição e fatiá-los com begins_with. Essa é a costura para o single-table design.
  • Coloque a dimensão de alta cardinalidade na chave de partição. O id do sensor tem milhares de valores, então espalha as escritas uniformemente. Uma chave de partição de baixa cardinalidade (digamos, region) cria uma partição quente.

Quando uma chave composta te morde

É um compromisso, não uma conveniência. A cilada: você escolhe uma chave de partição, lança, depois descobre um padrão de acesso que precisa de um agrupamento diferente — "todas as leituras acima de 30°C em toda a frota".

A tabela base não consegue responder isso; a chave de partição é fixa. Suas opções são um global secondary index com uma chave diferente, ou reestruturação.

Enumere suas leituras antes de comprometer o schema de chaves. Mudar uma chave primária significa uma migração de tabela, não um ALTER TABLE.

Próximos passos

Chaves compostas são a fundação sob coleções de itens, relacionamentos um-para-muitos e a maioria dos designs úteis de índice — leia single-table design e GSI vs LSI em seguida para ver aonde elas levam.

Esboce sua KeyConditionExpression no DynamoDB Expression Builder, depois experimente o DynoTable para navegar nas suas partições reais e ver a ordem de classificação se alinhar contra suas próprias tabelas.

Atualizado