Chaves de classificação com preenchimento zero no DynamoDB
Uma string DynamoDB classifica lexicograficamente - um caractere por
tempo, da esquerda para a direita - não numericamente. Então o "10" chega antes do "2", porque
"1" vem antes de "2". Preenchimento zero para uma largura fixa é como você cria strings
ordem corresponde à ordem numérica.
Por que "10" é classificado antes de "2" em uma chave de classificação DynamoDB?
Porque uma string DynamoDB é comparada lexicograficamente pela ordem de bytes UTF-8, não numericamente. O byte para "1" precede "2", então "10" chega antes de "2". Preencha cada número em uma largura fixa com zeros à esquerda - "2" torna-se "0000000002" - e a ordem das strings corresponde exatamente à ordem numérica.
- Ordem lexicográfica: números armazenados como strings são classificados como palavras.
"100","11","2"é o pedido que o DynamoDB lhe dá – não o que você quis dizer. - A correção: preencha cada número com uma largura fixa com zeros à esquerda, então
"2"torna-se"0000000002". Agora a ordem lexicográfica e numérica concordam. - Escolha uma largura uma vez: dimensione-a para o maior valor que você armazenará e adicium alguns dígitos. Alterar a largura posteriormente significa reescrever todas as teclas.
- Descendente gratuitamente: para classificar de maior para menor (o caso do placar), armazenar
maxValue - value, também preenchido com zeros – DynamoDB não tem classificação por atributo direção.
Por que as chaves de classificação de string traem você
Vindo do SQL, um ORDER BY score DESC em uma coluna inteira "simplesmente funciona" -
o mecanismo sabe que a coluna é numérica. DynamoDB não tem esse luxo de certa forma
chave que não é do tipo Number.
O DynamoDB compara chaves de classificação de string (S) por ordem de bytes do UTF-8, de acordo com o
Documentação da chave de classificação AWS.
Bytes, não magnitude. "9" (0x39) supera "10" porque seu primeiro byte supera
"1" (0x31). O comprimento é irrelevante – apenas o primeiro byte diferente decide.
Essa é a arma: no momento em que um número reside dentro de uma chave de classificação de string, cada
Query que percorre o intervalo retorna linhas em uma ordem que parece embaralhada.
Crie uma chave de classificação do placar
Faça uma tabela de classificação de arcade sazonal. Um por temporada mantém cada corrida do jogador, e você quer as melhores pontuações primeiro.
Modele-o com um em uma única coleção de itens:
leaderboardId(chave de partição) — por ex.SEASON#2026-SPRING.rankKey(tecla de classificação) — a pontuação preenchida com zeros mais um desempate.
Uma primeira tentativa ingênua armazena a pontuação bruta como uma string:
| leaderboardId | rankKey | playerHandle |
|---|---|---|
| SEASON#2026-SPRING | "9" | quickdraw |
| SEASON#2026-SPRING | "10" | ace_pilot |
| SEASON#2026-SPRING | "1500" | nightowl |
| SEASON#2026-SPRING | "240" | bytecrash |
Um Query em SEASON#2026-SPRING os retorna nesta ordem de bytes:
"10", "1500", "240", "9". A corrida de 9 pontos fica em último lugar e o
A corrida de 1.500 pontos está enterrada no meio. Inútil para uma tabela de classificação.
Pad para uma largura fixa
Escolha uma largura suficiente para a maior pontuação que você já registrou e, em seguida, pressione o botão esquerdo com zeros. Digamos que a pontuação seja máxima em dez milhões - são oito dígitos, então use dez dígitos para headroom:
| leaderboardId | rankKey | playerHandle |
|---|---|---|
| SEASON#2026-SPRING | "0000000009" | quickdraw |
| SEASON#2026-SPRING | "0000000010" | ace_pilot |
| SEASON#2026-SPRING | "0000000240" | bytecrash |
| SEASON#2026-SPRING | "0000001500" | nightowl |
Agora, todas as chaves têm o mesmo comprimento, portanto, a comparação byte a byte e os valores numéricos
comparação produz a ordem idêntica. Query ascendente dá 9, 10, 240, 1500. A matemática finalmente corresponde aos bytes.
A largura é uma porta unidirecional. Se você preencher até dez dígitos e uma pontuação posteriormente exceder
isso, um valor de 11 dígitos classifica antes de um valor de 10 dígitos - quebrando tudo novamente -
e consertá-lo significa reescrever todos os rankKey existentes. Superprovisionar a largura;
o custo é de alguns bytes.
Classificar em ordem decrescente: armazene a diferença
Uma tabela de classificação deseja a pontuação mais alta primeiro. DynamoDB pode ler uma chave de classificação
para frente ou para trás com ScanIndexForward: false, então descer geralmente é um
sinalizador de tempo de leitura - alcance-o primeiro.
Mas quando uma coleção de itens deve servir direções de classificação mistas, ou você deseja que o
pontuação máxima fisicamente primeiro, independentemente dos sinalizadores de leitura, inverta o próprio número.
Armazene maxValue - score, preenchido com zeros na mesma largura:
| score | inverted (9999999999 - score) | rankKey |
|---|---|---|
| 1500 | 9999998499 | "9999998499" |
| 240 | 9999999759 | "9999999759" |
| 10 | 9999999989 | "9999999989" |
| 9 | 9999999990 | "9999999990" |
A ordem crescente de bytes sobre o valor invertido agora produz as pontuações originais
alto para baixo: 1500, 240, 10, 9. O truque está no
Artigo do Amazon Dynamo de 2007
espírito - as chaves são bytes opacos, então você codifica a intenção em os bytes.
Adicione um desempate
Dois jogadores podem empatar. Uma pontuação simples e preenchida colide na chave de classificação e uma segunda write substituiria o primeiro (mesmo PK + SK). Anexe um sufixo exclusivo para que cada run é um item distinto e os empates são resolvidos de forma determinística:
rankKey = "<paddedScore>#<paddedTimestamp>#<playerId>"Por exemplo "0000001500#0000001719100800#p_8842". Mesma pontuação, anterior
timestamp ganha o slot mais alto - preencha o timestamp também ou reintroduz o
bug exato que você acabou de corrigir.
No DynoTable, você pode navegar pela tabela de classificação da temporada classificada pelo rankKey preenchido com zeros
e observe os valores preenchidos alinhando as linhas corretamente - prova de que as larguras estão corretas
antes de enviá-los.
Montando essa chave composta manualmente, é fácil definir a largura com os dedos. Gerando o
KeyConditionExpression para um Query "topo da temporada" no
construtor de expressão mantém o begins_with /
Sintaxe between honesta enquanto você experimenta larguras.

Armadilhas a evitar
- Preenchimento muito estreito. Todo o esquema é recolhido na primeira vez que um valor transborda a largura. Dimensione para o pior caso e adicione dígitos.
- Esquecendo o sinalizador de leitura. Se você ler apenas em ordem decrescente,
ScanIndexForward: falsepode ser tudo que você precisa - não use chaves invertidas quando um sinalizador fizer isso. - Larguras mistas em uma coleção. Cada chave que compartilha um intervalo de classificação deve usar o mesma largura. Uma migração que preenche novas linhas, mas não as antigas, as intercala erroneamente.
- Preenchendo o segmento errado. Em uma chave composta, preencha todos os segmentos numéricos que participa da ordenação — pontuação e carimbo de data/hora, não apenas a pontuação.
Próximos passos
O preenchimento zero é uma ferramenta no amplo
kit de ferramentas de design de chave de classificação; emparelhe-o com
coleções de itens quando você sobrecarrega uma chave para servir vários
padrões e apoie-se em um Query preciso em vez de um
Scan quando a ordem estiver correta.
Experimente DynoTable para navegar em uma tabela real e observar sua classificação preenchida com zeros as chaves se enquadram em ordem numérica antes de você enviar o esquema.


