Parte 03 - Maximize a economia de custos e escalabilidade do DynamoDB com índice secundário otimizado
Tags: braziliandevs, aws, cloud, dynamodb
Published: 2023-04-12 11:34:13

# Créditos

- Escrito originalmente por [Pete Naylor](https://twitter.com/pj_naylor), em [Maximize cost savings and scalability with an optimized DynamoDB secondary index](https://www.gomomento.com/blog/maximize-cost-savings-and-scalability-with-an-optimized-dynamodb-secondary-index).

---

## Entenda projeções e medição de dados. Esqueça a sobrecarga de GSI.

Esta é a terceira parte de uma série de artigos sobre modelagem de dados do DynamoDB, criada principalmente para ajudar os desenvolvedores usando DynamoDB a entender as práticas recomendadas e evitar seguir um caminho lamentável com técnicas equivocadas de "design de tabela única". No episódio anterior - isso é um show agora? - introduzimos índices secundários locais e globais (LSIs e GSIs). 

Hoje, vamos nos aprofundar para entender quais dados da tabela são projetados em um índice secundário e como isso contribui para o consumo de taxa de transferência. Também vamos separar uma das reviravoltas mais recentes no "design de tabela única" — sobrecarga de GSI — e explicar por que geralmente é uma péssima ideia sem nenhum lado positivo real. Preparado? Lá vamos nós!

# Quais mudanças na tabela base são relevantes para projeção em um índice secundário?

Ao definir um índice secundário, você pode escolher quais atributos serão copiados (projetados) das alterações de itens **relevantes** na tabela base: 

- `ALL` — todos os atributos no item da tabela base serão copiados para o índice secundário
- `INCLUDE` — somente a lista nomeada de atributos será copiada (e também os atributos de chave primária da tabela base e o índice secundário — estes são sempre incluídos)
- `KEYS_ONLY` — somente os atributos de chave primária da tabela base e o índice secundário serão copiados 

É assim que a medição funciona para índices secundários do DynamoDB: cada gravação feita em sua tabela base será considerada para a projeção de dados em cada um de seus índices secundários. Se a alteração do item na tabela base for **relevante** para o índice secundário, ela será projetada e haverá consumo da unidade de gravação - medido de acordo com o tamanho do item projetado. Haverá um custo de armazenamento para os dados projetados no índice secundário também. E lembre-se, conforme explicado no primeiro artigo desta série, `Query` e `Scan` (as únicas operações de leitura disponíveis para índices secundários) agregam o tamanho de todos os itens e, em seguida, arredondam para cima, para avaliar o total da medição da unidade de leitura. Se você mantiver a projeção de seus itens pequena, o índice custará menos e será dimensionado ainda mais antes de enfrentar qualquer tipo de preocupação importante. 

> Considere a projeção com muito cuidado para seu índice secundário. `ALL` parece simples, mas pode ser muito caro e pode inibir a escalabilidade de seu design em geral. **Projete apenas os atributos que você realmente precisa**.

Há mais detalhes nesta equação de eficiência para índices secundários. Você provavelmente está se perguntando por que continuo enfatizando a palavra **relevante** . Bem, é porque é realmente importante! Primeiro, como o DynamoDB oferece flexibilidade de esquema, os atributos definidos como a chave para seu índice secundário não precisam estar presentes em todos os itens de sua tabela (a menos que façam parte da chave primária dessa tabela). Se os atributos da chave do índice não estiverem presentes em um item da tabela, ele não será considerado **relevante** para projeção no índice. Você pode usar isso para criar um "índice esparso" — um poderoso mecanismo de filtragem — para localizar os dados necessários com o menor custo de armazenamento e taxa de transferência.

Um exemplo pode ser um banco de dados que armazena detalhes de status de milhões de tarefas - a grande maioria delas sendo concluída. Como podemos tornar as busca de tarefas que estão no status "enviado" mais fácil? Para tarefas que estão no status relevante da busca ("enviado"), crie um atributo que indique isso e adicione um índice secundário que seja definido por esse atributo. A presença do atributo efetivamente se torna um sinalizador - quando a tarefa for concluída, remova este atributo - a tarefa não estará mais visível no índice secundário quando a busca for realizada. 

![GSI waiting-jobs-index](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4l7bvfbqec01ybtvbz9c.png)

*[Nossa tabela base que rastreia o status da tarefa]*

![GSI waiting-jobs-index-ALL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1c4ytz9x5l58dawta260.png)

*[Índice secundário esparso que contém apenas tarefas aguardando atribuição]*

Agora vamos imaginar que, como parte do fluxo de trabalho para tarefas com status enviado, o item de tarefa na tabela seja atualizado cinco vezes para adicionar vários detalhes em atributos não-chave. Se esses atributos forem projetados para nosso índice secundário esparso de tarefas enviadas, o índice também precisará ser atualizado cinco vezes, consumindo várias unidades de gravação. Mas nosso índice secundário esparso realmente não tem utilidade para esses atributos - eles não são relevantes para o padrão de acesso que precisamos que o índice atenda. Portanto, escolhemos uma projeção `KEYS_ONLY` para o índice — ela mantém baixo o consumo de unidade de leitura, maximiza a escalabilidade de busca de tarefas, economiza dinheiro em armazenamento e evita várias gravações desnecessárias na projeção do índice. 

![GSI waiting-jobs-index-KEYS_ONLY](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gesd4qupjbtlofkib9mk.png)

*[O mesmo índice secundário, agora esparso com projeção KEYS_ONLY. Muito mais eficiente!]*

# O que é "sobrecarga de GSI" e por que é uma má ideia?

Em 2017, as equipes da Amazon estavam trabalhando duro para [migrar suas cargas de trabalho mais críticas](https://www.youtube.com/watch?v=qcuH2ikQkaM) de bancos de dados relacionais para o DynamoDB. Eles estavam aprendendo a pensar de maneira diferente sobre a modelagem de dados, olhando além da familiar terceira forma normal (3FN) e desnormalizando dados em itens e coleções de itens no DynamoDB. Naquela época, o DynamoDB suportava no máximo 5 GSIs por tabela, limite máximo. Em alguns casos raros, haveria uma equipe com uma tabela que exigia mais de 5 GSIs para cobrir todos os seus padrões de acesso. Para aqueles de nós que trabalham para dar suporte a essas equipes, percebemos que algumas das necessidades de índice podem ser esparsas e não se sobrepõem. Talvez com alguma adaptação instável pudéssemos usar o mesmo GSI para cobrir vários requisitos de padrão de acesso - isso poderia nos ajudar a trapacear no limite do GSI? Sim: era o último recurso, tinha implicações terríveis de eficiência e operabilidade - mas às vezes funcionava. Nós nos referimos a isso como "sobrecarga de GSI".

Avançando para dezembro de 2018, o DynamoDB [aumentou o limite de GSIs](https://aws.amazon.com/about-aws/whats-new/2018/12/amazon-dynamodb-increases-the-number-of-global-secondary-indexes-and-projected-index-attributes-you-can-create-per-table/) por tabela para 20. Alegria! Não há necessidade do hack feio de sobrecarga a partir de agora... certo? Bem, a equipe de engenharia pensou que sim, mas então surgiram algumas reviravoltas perturbadoras na fábula do "design de tabela única". 

> Acontece que, se você fizer coisas não naturais, desnecessárias, complexas e ineficientes para enviar dados completamente não relacionados para apenas uma tabela do DynamoDB sem motivo, acabará tendo que criar mais índices secundários para essa tabela. 

Se você estiver projetando dados com o objetivo de ter exatamente uma tabela (em vez de priorizar eficiência, flexibilidade e escalabilidade), é mais provável que você encontre o limite de GSIs por tabela - e então a mesma obsessão de "exatamente uma tabela" gere um desejo equivocado ter exatamente um GSI, o que leva à sobrecarga. Isso cria uma série de problemas. Na verdade, essa técnica não traz nenhum benefício — é uma má ideia. Aqui está o porquê: 

- Você provavelmente precisará fazer compensações para a projeção de dados que lhe custará dinheiro e prejudicará a escalabilidade do seu design. O menor denominador comum é projetar `ALL` e padronizar strings para atributos de chave primária (quando números seriam mais eficientes). Ai!
- Você perde a flexibilidade de poder varrer o índice secundário e recuperar apenas os dados de seu interesse. Essa é uma funcionalidade poderosa que se foi - sem nenhum motivo.
- Uma das grandes vantagens dos GSIs é que você pode excluí-los e recriá-los conforme necessário. Excluir um GSI não custa nada. Se você misturou vários requisitos de índice em um único GSI e em algum momento percebeu que não precisa indexar um de seus padrões, você não pode simplesmente excluir esse GSI. Você terá que (cuidadosamente) voltar para o design da sua tabela e fazer atualizações em massa relativamente caras (e potencialmente arriscadas). Você realmente não quer lidar com isso. 

# Lições importantes

Resumindo, não há benefício na "sobrecarga de GSI" – apenas pontos negativos. Não faça isso! Além disso, se você se preocupa com a otimização de custos e a escalabilidade, considere a **dispersão e a projeção mínima ao projetar índices secundários** no DynamoDB.

No próximo artigo desta série, pretendo desenvolver o que aprendemos até agora para explicar onde as coisas deram errado com o "design de tabela única" e por que interpretá-lo exatamente como uma tabela é um erro terrível (que as equipes da Amazon não estão fazendo). 

---

Se você quiser discutir esse tópico comigo, obter minha opinião sobre uma pergunta de modelagem de dados do DynamoDB que você tem ou sugerir tópicos para eu escrever em artigos futuros, entre em contato comigo no Twitter ([@pj_naylor](https://twitter.com/pj_naylor)) ou envie-me um [e-mail diretamente]mailto:petenaylor@momentohq.com)!