<h2>Data Modeling no DynamoDB</h2>
<p>O DynamoDB é um banco de dados NoSQL totalmente gerenciado da AWS que exige uma abordagem de modelagem fundamentalmente diferente de bancos relacionais. A chave está em pensar em <em>como você vai consultar os dados</em>, não apenas em como armazená-los. Diferentemente do SQL, você define uma chave primária (Partition Key + Sort Key opcional) que determina como os dados são distribuídos e recuperados.</p>
<p>Uma boa modelagem começa com identificar seus padrões de acesso. Se você precisa buscar usuários por ID e depois por email, não crie duas tabelas — use uma Partition Key (<code>userId</code>) e crie um GSI (Global Secondary Index) para email. Evite o máximo possível queries que varrem toda a tabela. O exemplo abaixo mostra uma tabela de e-commerce onde o padrão de acesso é: buscar pedidos por usuário, e secundariamente por status.</p>
<pre><code class="language-python">import boto3
from decimal import Decimal
dynamodb = boto3.resource('dynamodb')
Criar tabela com modelagem adequada
table = dynamodb.create_table(
TableName='Orders',
KeySchema=[
{'AttributeName': 'userId', 'KeyType': 'HASH'}, # Partition Key
{'AttributeName': 'orderId', 'KeyType': 'RANGE'} # Sort Key
],
AttributeDefinitions=[
{'AttributeName': 'userId', 'AttributeType': 'S'},
{'AttributeName': 'orderId', 'AttributeType': 'S'},
{'AttributeName': 'orderStatus', 'AttributeType': 'S'}
],
BillingMode='PAY_PER_REQUEST'
)
Inserir item com dados desnormalizados (padrão NoSQL)
table.put_item(Item={
'userId': 'user#123',
'orderId': 'order#456',
'orderStatus': 'DELIVERED',
'totalAmount': Decimal('199.99'),
'items': [
{'sku': 'PROD#001', 'quantity': 2},
{'sku': 'PROD#002', 'quantity': 1}
],
'createdAt': '2024-01-15T10:30:00Z'
})</code></pre>
<h2>Índices Secundários: GSI vs LSI</h2>
<h3>Global Secondary Indexes (GSI)</h3>
<p>GSIs permitem consultar dados usando uma chave primária diferente, com throughput independente. Você pode criar, atualizar e deletar GSIs sem parar a tabela. São úteis quando você precisa de padrões de acesso totalmente novos. Um GSI consome throughput <em>separado</em> da tabela base — você paga por leitura/escrita no GSI.</p>
<pre><code class="language-python"># Adicionar GSI para buscar pedidos por status
table.update_table(
AttributeDefinitions=[
{'AttributeName': 'orderStatus', 'AttributeType': 'S'},
{'AttributeName': 'createdAt', 'AttributeType': 'S'}
],
GlobalSecondaryIndexUpdates=[
{
'Create': {
'IndexName': 'OrderStatusIndex',
'KeySchema': [
{'AttributeName': 'orderStatus', 'KeyType': 'HASH'},
{'AttributeName': 'createdAt', 'KeyType': 'RANGE'}
],
'Projection': {'ProjectionType': 'ALL'},
'BillingMode': 'PAY_PER_REQUEST'
}
}
]
)
Consultar usando GSI
response = table.query(
IndexName='OrderStatusIndex',
KeyConditionExpression='orderStatus = :status',
ExpressionAttributeValues={':status': 'PENDING'}
)</code></pre>
<h3>Local Secondary Indexes (LSI)</h3>
<p>LSIs compartilham throughput com a tabela base e devem ser criados <em>no momento da criação da tabela</em>. São limitados a 10 GB por partition key. Use LSIs quando você quer ordenar resultados de forma diferente mantendo a mesma partition key. Para a maioria dos casos de produção, GSIs são preferíveis.</p>
<pre><code class="language-python"># Criar tabela com LSI (apenas na criação)
table = dynamodb.create_table(
TableName='UserActivity',
KeySchema=[
{'AttributeName': 'userId', 'KeyType': 'HASH'},
{'AttributeName': 'timestamp', 'KeyType': 'RANGE'}
],
AttributeDefinitions=[
{'AttributeName': 'userId', 'AttributeType': 'S'},
{'AttributeName': 'timestamp', 'AttributeType': 'N'},
{'AttributeName': 'activityType', 'AttributeType': 'S'}
],
LocalSecondaryIndexes=[
{
'IndexName': 'UserActivityTypeIndex',
'KeySchema': [
{'AttributeName': 'userId', 'KeyType': 'HASH'},
{'AttributeName': 'activityType', 'KeyType': 'RANGE'}
],
'Projection': {'ProjectionType': 'ALL'}
}
],
BillingMode='PAY_PER_REQUEST'
)</code></pre>
<h2>Capacity Modes em Produção</h2>
<h3>Provisioned vs On-Demand</h3>
<p>O modo <strong>Provisioned</strong> exige que você defina RCUs (Read Capacity Units) e WCUs (Write Capacity Units) antecipadamente. Cada RCU permite uma leitura fortemente consistente de até 4 KB por segundo; cada WCU permite uma escrita de até 1 KB por segundo. Use quando sua carga é previsível e consistente — é mais barato em geral.</p>
<p>O modo <strong>On-Demand</strong> (PAY_PER_REQUEST) cobra por requisição: aproximadamente $0.25 por milhão de RCUs e $1.25 por milhão de WCUs. Ideal para cargas impredizíveis, desenvolvimento e spikes de tráfego. Não há limite hard — a AWS escala automaticamente.</p>
<pre><code class="language-python"># Exemplo: Provisioned Mode para aplicação com carga conhecida
table = dynamodb.create_table(
TableName='ProductCatalog',
KeySchema=[{'AttributeName': 'productId', 'KeyType': 'HASH'}],
AttributeDefinitions=[{'AttributeName': 'productId', 'AttributeType': 'S'}],
BillingMode='PROVISIONED',
ProvisionedThroughputCapacity={
'ReadCapacityUnits': 100,
'WriteCapacityUnits': 50
}
)
Exemplo: On-Demand para novos serviços ou tráfego variável
table = dynamodb.create_table(
TableName='UserSessions',
KeySchema=[{'AttributeName': 'sessionId', 'KeyType': 'HASH'}],
AttributeDefinitions=[{'AttributeName': 'sessionId', 'AttributeType': 'S'}],
BillingMode='PAY_PER_REQUEST'
)</code></pre>
<h3>Prática em Produção</h3>
<p>Para produção, comece com On-Demand se não conhecer a carga. Monitore via CloudWatch — se seu padrão se torna previsível, migre para Provisioned com Auto Scaling. Configure alarmes para throttling (quando você esgota sua capacidade) e use o CloudWatch Insights para analisar hot partitions (uma partition key recebendo tráfego desproporcional).</p>
<pre><code class="language-python"># Configurar Auto Scaling para Provisioned Mode
autoscaling = boto3.client('application-autoscaling')
autoscaling.register_scalable_target(
ServiceNamespace='dynamodb',
ResourceId='table/Orders',
ScalableDimension='dynamodb:table:WriteCapacityUnits',
MinCapacity=5,
MaxCapacity=1000
)
autoscaling.put_scaling_policy(
PolicyName='OrdersWriteScaling',
ServiceNamespace='dynamodb',
ResourceId='table/Orders',
ScalableDimension='dynamodb:table:WriteCapacityUnits',
PolicyType='TargetTrackingScaling',
TargetTrackingScalingPolicyConfiguration={
'TargetValue': 70.0,
'PredefinedMetricSpecification': {
'PredefinedMetricType': 'DynamoDBWriteCapacityUtilization'
}
}
)</code></pre>
<h2>Otimizações e Boas Práticas</h2>
<p>Sempre use <strong>batch operations</strong> (BatchGetItem, BatchWriteItem) em vez de requisições individuais — reduz latência e custo. Implemente <strong>exponential backoff</strong> para throttling automático. Use <strong>sparse indexes</strong> — só projete atributos que você realmente consultará no GSI, economizando throughput. Evite scans; eles leem tudo e são caros. Se precisar migrar dados, use o DMS (Data Migration Service) ou Lambda com streams.</p>
<p>Considere o <strong>DynamoDB Streams</strong> para capturar mudanças em tempo real — perfeito para sincronizar com Elasticsearch ou disparar Lambdas. Na modelagem, use <strong>partition keys com boa distribuição</strong> — não use booleanos ou enums com poucos valores (criarão hot partitions). Para casos raros, use <strong>Query com FilterExpression</strong>, mas lembre que o filtro é aplicado <em>após</em> a leitura, portanto ainda consome RCU.</p>
<h2>Conclusão</h2>
<p>DynamoDB exige <strong>pensar primeiro em padrões de acesso</strong>, não em estrutura de dados. Domine GSIs (criação flexível, throughput independente), use On-Demand em produção inicial e migre para Provisioned com Auto Scaling conforme a carga se estabiliza. Monitore hot partitions e throttling no CloudWatch — a escalabilidade é automática, mas uma boa modelagem e escolha de chaves determinam seu custo e performance final.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html" target="_blank" rel="noopener noreferrer">AWS DynamoDB Developer Guide - Data Modeling</a></li>
<li><a href="https://www.dynamodbguide.com/" target="_blank" rel="noopener noreferrer">DynamoDB Design Patterns - Alex DeBrie</a></li>
<li><a href="https://pages.awscloud.com/rs/112-TZM-766/images/DynamoDB%20Deep%20Dive%20Advanced%20Design%20Patterns%20-%20DAT403.pdf" target="_blank" rel="noopener noreferrer">AWS re:Invent 2019 - DynamoDB Deep Dive</a></li>
<li><a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html" target="_blank" rel="noopener noreferrer">Boto3 DynamoDB Resource Documentation</a></li>
<li><a href="https://aws.amazon.com/dynamodb/pricing/" target="_blank" rel="noopener noreferrer">DynamoDB On-Demand vs Provisioned - AWS Pricing</a></li>
</ul>