Avançado8 min de leitura

Sobrecarga de chave no DynamoDB

Vindo do SQL, uma coluna significa uma coisa para sempre: orders.created_at é sempre um data, users.email é sempre um e-mail. Sobrecarga de teclas acaba com isso. Você forneça nomes genéricos à partição e - pk, sk - e deixe cada tipo de item coloque um significado diferente neles. Uma mesa, muitas entidades, uma forma.

O que é sobrecarga de teclas no DynamoDB?

A sobrecarga de chave é o armazenamento de muitos tipos de entidade em uma tabela sob nomes de chave genéricos como pk/sk, codificando o tipo no valor (USER#u_3001, INVOICE#2026-0014). O nome do atributo permanece neutro para que usuários, faturas e eventos compartilhem uma partição; o valor carrega o tipo e um prefixo de chave de classificação permite que um Query divida cada entidade por meio de begins_with.

  • Nomes de chaves genéricas, valores digitados. Nomeie suas chaves como pk/sk e coloque a entidade digite o valor: pk = "TENANT#acme", sk = "USER#u_3001". O nome é idiota; o valor carrega o tipo.
  • É o que faz o design de tabela única funcionar. Sem sobrecarga, uma tabela compartilhada é apenas uma gaveta de lixo. Com ele, cada entidade fica em uma partição que você pode Query.
  • begins_with é a recompensa. Um prefixo de tipo na chave de classificação permite que um Query extraia uma entidade inteira, ou uma fatia dela, sem Scan e sem filtro.
  • O custo: legibilidade. Um dump pk/sk bruto não diz nada. Você precisa de um visualizador que decodifica os prefixos, ou você estará olhando para as strings.

Por que os nomes genéricos superam os reais

O DynamoDB oferece no máximo dois atributos-chave por tabela, e um Query só pode ter como alvo um chave de partição única. Portanto, se você nomear sua chave userId, apenas os itens do usuário poderão residir essa mesa de forma limpa - todo o resto precisa falsificar um userId ou passar para sua própria mesa.

A sobrecarga evita isso. Um nome neutro como pk não se compromete com nenhuma entidade, portanto, um usuário, uma fatura e um evento de auditoria podem compartilhar o mesmo atributo-chave e a mesma mesa. O valor, e não o nome do atributo, diz qual é o item.

Este é o movimento que transforma design de mesa única de teoria em algo que você pode realmente questionar. A tabela compartilhada é o contêiner; a sobrecarga é o que permite que entidades distintas coexistam dentro dela.

Um exemplo de multilocatário

Digamos que você execute um produto de faturamento SaaS. Cada inquilino tem membros, faturas e uma auditoria trilha. Em vez de três tabelas, coloque tudo em uma e sobrecarregue as chaves:

pkskattributes
TENANT#acmeMETAname="Acme Inc", plan="team"
TENANT#acmeUSER#u_3001email, role="admin"
TENANT#acmeUSER#u_3002email, role="member"
TENANT#acmeINVOICE#2026-0014amount_cents, status="paid"
TENANT#acmeINVOICE#2026-0015amount_cents, status="open"
TENANT#acmeEVENT#2026-06-23T09:12Zactor="u_3001", action="invite"

Cada linha compartilha pk = "TENANT#acme", então elas formam um — todas co-localizados, todos acessíveis em uma única leitura de partição.

Partição: INQUILINO#acmesk: METAsk: USUÁRIO#u_3001sk: FATURA#2026-0015sk: EVENTO#2026-06-23T09:12ZUma consulta

O prefixo sort-key está fazendo o verdadeiro trabalho. Ele agrupa entidades e as ordena.

Consulte a coleção sobrecarregada

Como o tipo reside no prefixo da chave de classificação, o begins_with divide a partição em entidade sem digitalizar nada:

Query pk = "TENANT#acme"  -- the entire tenant, every type
Query pk = "TENANT#acme" AND begins_with(sk, "USER#")  -- just members
Query pk = "TENANT#acme" AND begins_with(sk, "INVOICE#")  -- just invoices

Você paga apenas pelos itens que a condição corresponde, não pela partição inteira - o oposto de um Scan filtrado, onde você paga para ler linhas você então joga fora. AWS chama isso de condição chave; ele roda nas chaves antes quaisquer dados saem da partição.

Se você construir essa condição begins_with manualmente, acerte as tags de tipo - um erro perdido USERS# em vez de USER# não retorna nada, silenciosamente. O construtor de expressão gera o KeyConditionExpression e o ExpressionAttributeValues mapeiam para que os prefixos corresponda ao que você realmente escreveu.

Sobrecarregue o índice também

O mesmo truque se aplica a um . Dê nomes de chave genéricos – gsi1pk, gsi1sk – e deixe cada entidade escrever o que precisar. Um índice então responde aos padrões tabela base não pode.

pkskgsi1pkgsi1sk
TENANT#acmeINVOICE#2026-0015STATUS#open2026-06-30
TENANT#acmeINVOICE#2026-0014STATUS#paid2026-06-12
TENANT#betaINVOICE#2026-0099STATUS#open2026-06-25

Agora o Query gsi1 WHERE gsi1pk = "STATUS#open" lista todas as faturas em aberto em todos inquilinos, ordenados por data de vencimento — uma exibição de partição cruzada com escopo de inquilino da tabela base as chaves nunca poderiam servir. Uma entidade diferente pode reutilizar gsi1 com seu próprio significado (digamos gsi1pk = "ROLE#admin"), portanto, um índice cobre várias leituras. Apenas lembre-se de um GSI é eventualmente consistente – suas escritas ficam atrasadas em relação à tabela base.

Faça isso no DynoTable

Chaves sobrecarregadas brutas são hostis à leitura: INVOICE#2026-0015 e EVENT#2026-06-23T09:12Z desfocam-se em uma lista plana. Um visualizador que agrupa por particionar e revelar os prefixos transforma a gaveta de lixo eletrônico novamente em entidades.

DynoTable navegando na coleção de itens de um locatário - itens META, USER, INVOICE e EVENT agrupados em uma única chave de partição sobrecarregada.
DynoTable navegando na coleção de itens de um locatário - itens META, USER, INVOICE e EVENT agrupados em uma única chave de partição sobrecarregada.

Armadilhas

  • Escolha os delimitadores uma vez e nunca os altere. # é a convenção. Misturando # e o : entre entidades quebra o begins_with de maneiras que nada avisa.
  • Não sobrecarregue valores que precisam de matemática de intervalo. Uma chave de classificação de INVOICE#2026-0015 classifica lexicalmente, não numericamente - identifica e usa ISO-8601 datas para que a ordem das strings corresponda à ordem que você quer dizer.
  • Reserve o namespace do prefixo. Dois tipos de entidade que iniciam USER (digamos USER# e USERGROUP#) colidirão sob begins_with(sk, "USER"). Faça prefixos inequívocos desde o primeiro caractere.
  • Planeje a leitura antes das chaves. A sobrecarga atende aos padrões de acesso que você enumerado. Se você ainda não sabe suas leituras, veja design de tabela única primeiro - as chaves estão no downstream das consultas.

Mapeie uma partição e baixe DynoTable para navegar por sua própria chaves sobrecarregadas e observe um Query retirar um inquilino inteiro de uma vez.

Custo de consulta em uma partição sobrecarregada

Listando todos os membros do TENANT#acme com begins_with(sk, "USER#") lê apenas linhas de usuário – não faturas ou eventos – porque a condição principal é filtrada antes que os dados saiam da partição. Em um inquilino com 200 usuários (2 KB cada) e 5.000 eventos de auditoria (1 KB cada), essa consulta toca ~ 400 KB (~ 100 RCU eventualmente consistentes). Um Scan em toda a mesa para encontrar usuários mediria cada item em cada inquilino.

Cole itens representativos sobrecarregados no calculadora de tamanho de item e, em seguida, estimar a lista consultas na calculadora de preços.

Projete com a ferramenta de tabela única

Insira entidades (Locatário, Usuário, Fatura, Evento) e padrões de acesso ("listar usuários para inquilino", "faturas em aberto entre inquilinos") no ferramenta de design de mesa única. Ele propõe Modelos pk/sk e chaves GSI que correspondem aos prefixos de sobrecarga que você usará em produção — antes de confirmar o CloudFormation.

Emite consultas de padrões

Depois que os prefixos forem corrigidos, crie condições-chave no construtor de expressão e exporte um paginado programa do construtor de consultas. Erros de digitação de prefixo (USER# vs USERS#) retornam conjuntos vazios sem erros - expressões geradas reduzir esse modo de falha silencioso.

Registro de prefixo do tipo de entidade

Mantenha uma tabela interna curta que os desenvolvedores possam consultar:

EntidadePrefixo de classificaçãoExemplo SKFatia de consulta
Meta do inquilinoMETAMETAObtenção de item único
UsuárioUSER#USER#u_3001begins_with(sk, "USER#")
FaturaINVOICE#INVOICE#2026-0015begins_with(sk, "INVOICE#")
EventoEVENT#EVENT#2026-06-23T09:12Zcauda ordenada no tempo com leitura descendente

Novos tipos de entidade devem escolher prefixos que não colidam sob begins_with de prefixos existentes - USER# e USERGROUP# correspondem a begins_with(sk, "USER") a menos que você aumente ou separe o delimitador com cuidado.

Atualizado