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/ske 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 umQueryextraia uma entidade inteira, ou uma fatia dela, semScane sem filtro.- O custo: legibilidade. Um dump
pk/skbruto 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:
| pk | sk | attributes |
|---|---|---|
| TENANT#acme | META | name="Acme Inc", plan="team" |
| TENANT#acme | USER#u_3001 | email, role="admin" |
| TENANT#acme | USER#u_3002 | email, role="member" |
| TENANT#acme | INVOICE#2026-0014 | amount_cents, status="paid" |
| TENANT#acme | INVOICE#2026-0015 | amount_cents, status="open" |
| TENANT#acme | EVENT#2026-06-23T09:12Z | actor="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.
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.
| pk | sk | gsi1pk | gsi1sk |
|---|---|---|---|
| TENANT#acme | INVOICE#2026-0015 | STATUS#open | 2026-06-30 |
| TENANT#acme | INVOICE#2026-0014 | STATUS#paid | 2026-06-12 |
| TENANT#beta | INVOICE#2026-0099 | STATUS#open | 2026-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.

Armadilhas
- Escolha os delimitadores uma vez e nunca os altere.
#é a convenção. Misturando#e o:entre entidades quebra obegins_withde maneiras que nada avisa. - Não sobrecarregue valores que precisam de matemática de intervalo. Uma chave de classificação de
INVOICE#2026-0015classifica 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(digamosUSER#eUSERGROUP#) colidirão sobbegins_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:
| Entidade | Prefixo de classificação | Exemplo SK | Fatia de consulta |
|---|---|---|---|
| Meta do inquilino | META | META | Obtenção de item único |
| Usuário | USER# | USER#u_3001 | begins_with(sk, "USER#") |
| Fatura | INVOICE# | INVOICE#2026-0015 | begins_with(sk, "INVOICE#") |
| Evento | EVENT# | EVENT#2026-06-23T09:12Z | cauda 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.


