Desnormalização em DynamoDB
Vindo de SQL, a desnormalização parece um pecado – dados duplicados, nenhum fonte da verdade. Em DynamoDB esse é o ponto principal. Não há junções, então você copie os dados relacionados no item que precisa deles e leia-os de uma só vez.
O que é desnormalização em DynamoDB?
A desnormalização em DynamoDB significa copiar os dados relacionados no item que os lê, de modo que uma única consulta retorna tudo de uma só vez. Como DynamoDB não tem junções, você pré-junta no momento da gravação em vez de unir as tabelas no momento da leitura. A desvantagem é a desatualização – apenas valores duplicados que raramente mudam.
- Sem junções significa que você pré-ingressa no momento da gravação. Armazene o valor relacionado no item que o lê, portanto, uma consulta nunca precisa de uma segunda pesquisa.
- Dois tipos. Incorporar dados aninhados em um atributo complexo em um item ou duplicar um valor em muitos itens.
- A arma está obsoleta. Quando a fonte muda, todas as cópias estão erradas até você espalhar a atualização. Apenas valores duplicados que raramente mudam.
- Ele compra leituras, não gravações. Você troca mais (e com mais cuidado) gravações por leituras baratas e de solicitação única.
Por que não há junções para recorrer
Um JOIN relacional remonta as linhas normalizadas no momento da leitura. DynamoDB não tem
join — um Query lê ume devolve exatamente o que está armazenado
lá. Nada une duas mesas para você. (Na produção, leia
caminho, de qualquer maneira - para a auditoria ad-hoc ou verificação de desvio, SQL de DynoTable
Workbench executa um JOIN real no lado do cliente DynamoDB.)
Portanto, os dados já devem estar moldados para a leitura. Se uma tela precisa de uma postagem e o nome do autor, esse nome deve estar em algum lugar que a postagem lida já toque. O artigo do Amazon Dynamo de 2007 tornou esse comércio explícito: abandone os recursos relacionais para obter leituras previsíveis em escala - a negociação DynamoDB agora entrega como leituras de milissegundos de um dígito.
Padrão 1 — incorporar com um atributo complexo
Os atributos DynamoDB podem conter mapas e listas aninhados, não apenas escalares. Então uma forma comum de desnormalização é colocar um objeto filho diretamente dentro de seu item pai em vez de fornecer seu próprio item.
Uma postagem com suas tags e um pequeno instantâneo do autor, tudo em um item:
| PK | SK | author | tags |
|---|---|---|---|
| POST#9f3 | META | {id: U#12, name: "Mara Vance"} | ["dynamodb","aws"] |
Um GetItem retorna a postagem, as tags e o bloco do autor juntos. Não
segunda leitura. Isso é ótimo para dados que pertencem ao pai e estão limitados
tamanho – um punhado de tags, um instantâneo do autor.
Um único item DynamoDB atinge o máximo de 400 KB, atributo nomes e valores incluídos (Cotas de serviço). Incorpore uma lista ilimitada (cada comentário em uma postagem viral) e você a superará.
Padrão 2 – duplicar um valor entre itens
O caso do blog é o do livro didático. Você lista postagens e deseja que cada linha mostre o nome de exibição do autor — mas você não quer uma segunda leitura por postagem para buscá-lo.
Então você escreve o nome do autor em cada item da postagem quando a postagem é criada:
| PK | SK | authorId | authorName | title |
|---|---|---|---|---|
| POST#9f3 | META | U#12 | "Mara Vance" | "Modeling 1:N" |
| POST#a71 | META | U#12 | "Mara Vance" | "Sparse GSIs" |
| POST#b04 | META | U#88 | "Lio Tan" | "Query vs Scan" |
UMsobre postagens (digamos GSI1PK = "POST", ou uma digitada pelo autor) renderiza o todo
lista — título e autor — sem pesquisa por linha. begins_with na chave de partição não é um
coisa; um Query precisa de igualdade de chave de partição, então com chaves de partição por postagem a lista vem
do GSI, não um Query sobre POST#. O nome do autor é desnormalizado:
a cópia canônica reside em USER#12, e cada postagem carrega sua própria cópia.
O comércio está aí. Você transformou uma leitura N+1 em uma leitura, ao custo de
segurando "Mara Vance" em N+1 lugares.
Incorporar vs. duplicar — qual
| Incorporar (atributo complexo) | Duplicar (copiar entre itens) | |
|---|---|---|
| Forma | filho aninhado dentro do pai | mesmo valor em muitos itens |
| Melhor para | dados limitados e de propriedade dos pais | um valor compartilhado que muitos itens exibem |
| Leia | um GetItem | um Query |
| Custo de atualização | reescrever o item pai | distribua cada cópia |
| Risco de tamanho | Limite de item de 400 KB | nenhum por item |
Use incorporar quando o filho só aparecer com o pai. Alcançar duplicado quando muitos itens independentes precisam mostrar o mesmo valor compartilhado.
A arma de fogo: cópias obsoletas
Mara renomeia-se para "Mara V." Você atualiza USER#12. Cada item de postagem ainda
diz "Mara Vance" até você ir consertá-los.
Portanto, atualizar um valor duplicado é uma gravação de fan-out, não uma linha única. Você consulta cada item afetado e reescrever cada um - de preferência protegido para que você toque apenas nas linhas que ainda mantêm o valor antigo:
UPDATE POST#9f3
SET authorName = "Mara V."
WHERE authorName = "Mara Vance"
Você pode compor aquele SET condicional contra authorName no
Expression Builder e copie o arquivo gerado
UpdateExpression e ConditionExpression direto no seu código.
Fan-out é uma gravação por item. Query o GSI digitado pelo autor para esse autor postagens e, em seguida, emita as atualizações. A sequência:
Cada alteração na fonte é uma consulta mais uma gravação por cópia. Em DynoTable o fan-out chega à área de teste primeiro, como uma comparação revisável por atributo por item - você vê cada cópia que é prestes a mudar antes que qualquer coisa seja enviada.
É por isso que a regra é apenas valores duplicados que raramente mudam. Uma exibição nome, um nível de plano, um rótulo de categoria – tudo bem. Um contador ao vivo ou editado com frequência campo - não; o fan-out vai te comer vivo.
Custo de gravação de distribuição
Cada cópia atualizada é uma gravação faturada separada. Em us-east-1 sob demanda,
atualizar 50 itens de postagem após a renomeação de um autor custa 50 × WCU - normalmente
1 WCU por KB por item quando cada linha de postagem for ≤ 1 KB. O lado lido permanece
um Query; o lado da gravação é dimensionado de acordo com quantas duplicatas você mantém. Estimativa
ambos os caminhos na calculadora de preços.
Quando a normalização ainda vence
Se um valor muda frequentemente ou um item é lido por pessoas genuinamente imprevisíveis padrões, mantenha-o normalizado e aceite a leitura extra. A desnormalização é um otimização para padrões de acesso conhecidos e com muita leitura — não é um padrão a ser aplicado em todos os lugares. Junte-se previamente às leituras que você realmente executa e deixe o resto em paz.
Para decidir onde esses atributos duplicados residem, modele os padrões de acesso primeiro - consulte design de tabela única e, para leitura lado da negociação, Query vs Scan.
Baixar DynoTable para inspecionar uma tabela desnormalizada, identificar quais cópias
foram desviados e execute a atualização de distribuição em seus próprios dados. É
SQL Workbench pode até JOIN a fonte da verdade contra
as cópias para encontrar o desvio em uma consulta.