

# Modelagem de dados para tabelas do DynamoDB
<a name="data-modeling"></a>

Antes de nos aprofundarmos na modelagem de dados, é importante entender alguns fundamentos do DynamoDB. O DynamoDB é um banco de dados NoSQL de chave-valor que permite um esquema flexível. O conjunto de atributos de dados, além dos atributos de chave de cada item, pode ser uniforme ou distinto. O esquema de chaves do DynamoDB está na forma de uma chave primária simples, em que uma chave de partição identifica exclusivamente um item, ou na forma de uma chave primária composta, em que uma combinação de chave de partição e chave de classificação define exclusivamente um item. A chave de partição é em hash para determinar a localização física dos dados e recuperá-los. Portanto, é importante escolher um atributo de alta cardinalidade e escalável horizontalmente como chave de partição para garantir uma distribuição uniforme dos dados. O atributo de chave de classificação é opcional no esquema de chaves, e ter uma chave de classificação permite modelar relações de um para muitos e criar coleções de itens no DynamoDB. As chaves de classificação, também são chamadas de chaves de intervalo, são usadas para classificar itens em uma coleção de itens e também permitem operações flexíveis baseadas em intervalos.

Para ver mais detalhes e conhecer as práticas recomendadas sobre o esquema de chaves do DynamoDB, você pode consultar o seguinte:
+ [Partições e distribuição de dados no DynamoDB](HowItWorks.Partitions.md) 
+ [Práticas recomendadas para projetar e usar chaves de partição de maneira eficaz no DynamoDB](bp-partition-key-design.md) 
+ [Práticas recomendadas para usar chaves de classificação para organizar dados no DynamoDB](bp-sort-keys.md) 
+ [Escolher a chave de partição correta do DynamoDB](https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/) 

Os índices secundários geralmente são necessários para oferecer compatibilidade com padrões de consulta adicionais no DynamoDB. Eles são tabelas de sombra em que os mesmos dados são organizados por meio de um esquema de chaves diferente em comparação com a tabela base. Um índice secundário local (LSI) compartilha a mesma chave de partição da tabela base e permite ter uma chave de classificação alternativa, o que possibilita que ele compartilhe a capacidade da tabela base. Um índice secundário global (GSI) pode ter uma chave de partição diferente, bem como um atributo de chave de classificação diferente da tabela base, o que significa que o gerenciamento de throughput de um GSI é independente da tabela base.

Para ver mais detalhes sobre índices secundários e conhecer as práticas recomendadas, você pode consultar o seguinte:
+ [Melhorar o acesso aos dados com índices secundários no DynamoDB](SecondaryIndexes.md) 
+ [Práticas recomendadas para uso de índices secundários no DynamoDB](bp-indexes.md) 

Vamos analisar a modelagem de dados um pouco mais de perto. A criação de um esquema flexível e altamente otimizado no DynamoDB, ou em qualquer banco de dados NoSQL, pode ser uma habilidade difícil de aprender. O objetivo deste módulo é ajudar você a desenvolver um fluxograma mental para criar um esquema que conduza você do caso de uso à produção. Começaremos com uma introdução à escolha básica de qualquer design: uma única tabela versus várias tabelas. Em seguida, analisaremos a variedade de padrões de design (componentes básicos) que podem ser usados para obter vários resultados organizacionais ou de performance para sua aplicação. Por fim, estamos incluindo uma variedade de pacotes completos de design de esquemas para diferentes casos de uso e setores.

![\[Imagem mostrando a relação conceitual entre os dados, os componentes abaixo deles e a base sob os componentes.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesign.png)


**Topics**
+ [Coleções de itens: como modelar relações de um para muitos no DynamoDB](WorkingWithItemCollections.md)
+ [Fundamentos da modelagem de dados no DynamoDB](data-modeling-foundations.md)
+ [Componentes básicos da modelagem de dados no DynamoDB](data-modeling-blocks.md)
+ [Pacotes de design de esquema de modelagem de dados no DynamoDB](data-modeling-schemas.md)
+ [Práticas recomendadas para modelagem de dados relacionais no DynamoDB](bp-relational-modeling.md)

# Coleções de itens: como modelar relações de um para muitos no DynamoDB
<a name="WorkingWithItemCollections"></a>

No DynamoDB, uma *coleção de itens* é um grupo de itens que compartilham o mesmo valor de chave de partição, o que significa que os itens estão relacionados. As coleções de itens são o mecanismo primário para modelar relações de um para muitos no DynamoDB. As coleções de itens só podem existir em tabelas ou índices configurados para usar uma [chave primária composta](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey).

**nota**  
Podem existir coleções de itens em uma tabela base ou em um índice secundário. Para obter mais informações especificamente sobre como as coleções de itens interagem com índices, consulte [Conjuntos de itens em índices secundários locais](LSI.md#LSI.ItemCollections).

Considere a seguinte tabela que mostra três usuários diferentes e seus inventários no jogo:

![\[Três coleções de itens diferentes com atributos distintos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/item_collection.png)


Para alguns itens em cada coleção, a chave de classificação é uma concatenação composta de informações usadas para agrupar dados, como `inventory::armor`, `inventory::weapon` ou `info`. Cada coleção de itens pode ter uma combinação diferente desses atributos como a chave de classificação. O usuário `account1234` tem o item `inventory::weapons`, enquanto o usuário `account1387` não tem (porque ainda não o encontrou). O usuário `account1138` usa apenas dois itens para a chave de classificação (já que ainda não tem inventário) enquanto os outros usuários usam três.

O DynamoDB permite recuperar itens seletivamente dessas coleções para fazer o seguinte:
+ Recuperar todos os itens de um usuário específico
+ Recuperar apenas um item de um usuário específico
+ Recuperar todos os itens de um tipo específico pertencentes a determinado usuário

## Acelerar as consultas organizando os dados com coleções de itens
<a name="WorkingWithItemCollections.Example"></a>

Nesse exemplo, cada um dos itens nas três coleções representa um jogador e o modelo de dados que escolhemos, com base nos padrões de acesso do jogo e do jogador. De quais dados o jogo precisa? Quando ele precisa desses dados? Com que frequência ele precisa dos dados? Qual é o custo de fazer isso dessa maneira? Essas decisões de modelagem de dados foram tomadas com base nas respostas a essas perguntas.

Nesse jogo, há uma página diferente apresentada ao jogador para o inventário de armas e outra página para a armadura. Quando o jogador abre o inventário, as armas são mostradas primeiro porque queremos que a página seja carregada muito rapidamente, enquanto as páginas de inventário subsequentes podem ser carregadas depois disso. Como cada um desses tipos de item pode ser bastante grande à medida que o jogador adquire mais itens no jogo, decidimos que cada página de inventário seria seu próprio item na coleção do jogador no banco de dados. 

A seção a seguir fala mais sobre como você pode interagir com as coleções de itens por meio da operação `Query`.

**Topics**
+ [Acelerar as consultas organizando os dados com coleções de itens](#WorkingWithItemCollections.Example)

# Fundamentos da modelagem de dados no DynamoDB
<a name="data-modeling-foundations"></a>

Esta seção aborda a camada básica, examinando os dois tipos de design de tabela: tabela única e várias tabelas.

![\[Imagem mostrando a relação conceitual entre os dados, os componentes abaixo deles e a base sob os componentes. Ênfase sobre a base.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignFoundation.png)


## Conceitos básicos do design de tabela única
<a name="data-modeling-foundations-single"></a>

Uma das opções de base para o esquema do DynamoDB é o **design de tabela única**. O design de tabela única é um padrão que permite armazenar vários tipos (entidades) de dados em uma única tabela do DynamoDB. Seu objetivo é otimizar os padrões de acesso aos dados, melhorar a performance e reduzir os custos, eliminando a necessidade de manter várias tabelas e relacionamentos complexos entre elas. Isso é possível porque o DynamoDB armazena itens com a mesma chave de partição (conhecida como coleção de itens) nas mesmas partições. Nesse design, diferentes tipos de dados são armazenados como itens na mesma tabela e cada item é identificado por uma chave de classificação exclusiva.

![\[Imagem mostrando uma tabela e como a chave de classificação é usada para diferenciar cada item por tipo de entidade na mesma coleção de itens UserID.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SingleTableSchema.png)


**Vantagens**
+ Oferece localidade de dados para atender a consultas para vários tipos de entidades em uma única chamada de banco de dados.
+ Reduz os custos financeiros gerais e de latência das leituras:
  + Uma única consulta para dois itens com menos de 4 KB no total corresponde a 0,5 RCU com consistência final.
  + Duas consultas para dois itens com menos de 4 KB no total corresponde a 1 RCU com consistência final (0,5 RCU cada).
  + O tempo para exibir duas chamadas de banco de dados separadas normalmente será maior do que o de uma única chamada.
+ Reduz o número de tabelas a serem gerenciadas:
  + Não é necessário manter permissões em vários perfis ou políticas do IAM. 
  + O gerenciamento de capacidade da tabela é distribuído proporcionalmente entre todas as entidades, o que geralmente resulta em um padrão de consumo mais previsível.
  + O monitoramento requer menos alarmes.
  + As chaves de criptografia gerenciadas pelo cliente só precisam ser alternadas em uma única tabela.
+ Suaviza o tráfego para a tabela:
  + Ao agregar vários padrões de uso à mesma tabela, o uso geral tende a ser mais suave (da mesma forma que a performance de um índice de ações tende a ser mais suave do que qualquer ação individual), o que é mais adequado para conseguir maior utilização com tabelas de modo provisionado.

**Desvantagens**
+ A curva de aprendizado pode ser pronunciada devido ao design paradoxal em comparação com bancos de dados relacionais.
+ Os requisitos de dados devem ser consistentes em todos os tipos de entidade.
  + Os backups são tudo ou nada; portanto, se alguns dados não forem essenciais, pense na possibilidade de mantê-los em uma tabela separada.
  + A criptografia da tabela é compartilhada entre todos os itens. Para aplicações de vários locatários com requisitos individuais de criptografia de locatário, seria necessária a criptografia do lado do cliente.
  + As tabelas com uma combinação de dados históricos e dados operacionais não serão tão beneficiadas com a habilitação da classe de armazenamento de acesso infrequente. Para obter mais informações, consulte . [Classes de tabelas do DynamoDB](HowItWorks.TableClasses.md) 
+ Todos os dados alterados serão propagados para o DynamoDB Streams mesmo que seja necessário processar somente um subconjunto de entidades.
  + Graças aos filtros de eventos do Lambda, isso não afetará sua fatura ao usar o Lambda, mas haverá um custo adicional se você usar a Kinesis Consumer Library. 
+ Quando se usa o GraphQL, é mais difícil de implementar o design de tabela única.
+ Ao usar clientes SDK de nível superior, como o [`DynamoDBMapper`](DynamoDBMapper.md) do Java ou o [Enhanced Client](DynamoDBEnhanced.md), pode ser mais difícil processar resultados porque na mesma resposta pode haver itens associados a classes diferentes.

**Quando utilizar**

O design de tabela única funciona bem para aplicativos que frequentemente consultam vários tipos de entidades juntos ou precisam manter relacionamentos entre diferentes tipos de dados. É particularmente eficaz quando seus padrões de acesso se beneficiam da localidade de dados e quando você deseja minimizar a sobrecarga de gerenciar várias tabelas.

## Conceitos básicos do design de várias tabelas
<a name="data-modeling-foundations-multi"></a>

A segunda opção de base para o nosso esquema do DynamoDB é o design de várias tabelas****. O design de várias tabelas é um padrão mais parecido com um design de banco de dados tradicional em que você armazena um único tipo (entidade) de dados em cada tabela do DynamoDB. Os dados em cada tabela ainda serão organizados por chave de partição para que a performance e a escalabilidade de um único tipo de entidade sejam otimizadas, mas as consultas em várias tabelas deverão ser feitas de forma independente.

![\[Imagem mostrando uma tabela do fórum com uma lista de fóruns e alguns dados agregados.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/MultipleTable1.png)


![\[Imagem mostrando uma tabela de tópicos contendo uma lista de tópicos particionados pelo fórum específico ao qual eles pertencem.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/MultipleTable2.png)


**Vantagens**
+ É mais simples de projetar para quem não está acostumado a trabalhar com design de tabela única. 
+ Possibilita uma implementação mais fácil de resolvedores do GraphQL devido ao mapeamento de cada resolvedor para uma única entidade (tabela).
+ Permite requisitos de dados exclusivos em diferentes tipos de entidade:
  + É possível fazer backups de tabelas individuais de missão crítica. 
  + É possível gerenciar a criptografia de cada tabela. Para aplicações de vários locatários com requisitos individuais de criptografia de locatário, tabelas de locatários separadas possibilitam que cada cliente tenha sua própria chave de criptografia.
  + Para obter todos os benefícios de redução de custos, a classe de armazenamento de acesso infrequente pode ser habilitada apenas nas tabelas com dados históricos. Para obter mais informações, consulte . [Classes de tabelas do DynamoDB](HowItWorks.TableClasses.md)
+ Cada tabela terá seu próprio fluxo de dados de alteração, permitindo que uma função do Lambda dedicada seja projetada para cada tipo de item, em vez de um único processador monolítico.

**Desvantagens**
+ Para padrões de acesso que exigem dados em várias tabelas, diversas leituras do DynamoDB serão necessárias e talvez os dados precisem ser processados e unidos no código do cliente.
+ As operações e o monitoramento de várias tabelas exigem mais alarmes do CloudWatch, e cada tabela deve ser escalada de forma independente.
+ As permissões de cada tabela precisarão ser gerenciadas separadamente. A adição de tabelas no futuro exigirá uma alteração em todos os perfis ou políticas essenciais do IAM.

**Quando utilizar**

Se os padrões de acesso da aplicação não precisarem consultar várias entidades ou tabelas ao mesmo tempo, o design de várias tabelas será uma abordagem adequada e suficiente.

# Componentes básicos da modelagem de dados no DynamoDB
<a name="data-modeling-blocks"></a>

Esta seção abordará a camada de componentes básicos que oferecem os padrões de design a serem utilizados na aplicação.

![\[Imagem mostrando a relação conceitual entre os dados, os componentes abaixo deles e a base sob os componentes. Ênfase sobre a base.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignBlocks.png)


**Topics**
+ [Componente básico: chave de classificação composta](#data-modeling-blocks-composite)
+ [Componente básico: multilocação](#data-modeling-blocks-multi-tenancy)
+ [Componente básico: índice esparso](#data-modeling-blocks-sparse-index)
+ [Componente básico: vida útil](#data-modeling-blocks-ttl)
+ [Componente básico: vida útil para arquivamento](#data-modeling-blocks-ttl-archival)
+ [Componente básico: particionamento vertical](#data-modeling-blocks-vertical-partitioning)
+ [Componente básico: fragmentação de gravação](#data-modeling-blocks-write-sharding)

## Componente básico: chave de classificação composta
<a name="data-modeling-blocks-composite"></a>

Quando as pessoas pensam em NoSQL, é possível que elas também o imaginem como não relacional. Em última análise, não há motivo que impeça a inserção de relações em um esquema do DynamoDB. Elas só parecem diferentes dos bancos de dados relacionais e das respectivas chaves externas. Um dos padrões mais importantes que podemos usar para desenvolver uma hierarquia lógica de nossos dados no DynamoDB é uma chave de classificação composta. A maneira mais comum de criar uma é separar cada camada da hierarquia (camada pai > camada filha > camada neta) com uma hashtag. Por exemplo, `PARENT#CHILD#GRANDCHILD#ETC`.

![\[Imagem mostrando um item em uma tabela com um ID de usuário como chave primária e uma combinação de outros atributos como chave de classificação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ShoppingCart.png)


Embora uma chave de partição no DynamoDB sempre exija o valor exato para consulta de dados, podemos aplicar uma condição parcial à chave de classificação da esquerda para a direita, de modo semelhante a percorrer uma árvore binária.

No exemplo acima, temos uma loja de comércio eletrônico em que é necessário manter o carrinho de compras em todas as sessões do usuário. Sempre que o usuário fizer login, talvez queira ver o carrinho de compras completo, incluindo itens salvos para outro momento. Porém, quando ele entra na finalização da compra, somente os itens no carrinho ativo devem ser carregados para compra. Como ambas as `KeyConditions` solicitam explicitamente as chaves de classificação CART, os dados adicionais da lista de desejos simplesmente são ignorados pelo DynamoDB no momento da leitura. Embora os itens salvos e ativos façam parte do mesmo carrinho, precisamos tratá-los de forma distinta em diferentes partes da aplicação. Portanto, aplicar uma `KeyCondition` ao prefixo da chave de classificação é a melhor maneira de recuperar somente os dados necessários para cada parte da aplicação.

**Principais atributos deste componente básico**
+ Os itens relacionados são armazenados lado a lado no mesmo local para tornar o acesso aos dados eficaz. 
+ Por meio de expressões `KeyCondition`, é possível recuperar seletivamente os subconjuntos da hierarquia, o que significa que não há desperdício de RCUs. 
+ Diferentes partes da aplicação podem armazenar os respectivos itens sob um prefixo específico, evitando itens sobrescritos ou gravações conflitantes.

## Componente básico: multilocação
<a name="data-modeling-blocks-multi-tenancy"></a>

Muitos clientes usam o DynamoDB para hospedar dados de aplicações de vários locatários. Para essas circunstâncias, nosso objetivo é projetar o esquema de uma forma que mantenha todos os dados de um único locatário em sua própria partição lógica da tabela. Essa ideia se baseia no conceito de coleção de itens, que é um termo para todos os itens em uma tabela do DynamoDB que têm a mesma chave de partição. Para obter mais informações sobre como o DynamoDB aborda a multilocação, consulte [Multilocação no DynamoDB](https://docs.aws.amazon.com/whitepapers/latest/multi-tenant-saas-storage-strategies/multitenancy-on-dynamodb.html). 

![\[Imagem mostrando uma tabela que pode representar um site de fotos com vários locatários. A chave primária é composta de usuários como chave de partição e diferentes fotos como chave de classificação. O atributo de cada item mostra o URL em que a foto está hospedada.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/MultiTenant.png)


Neste exemplo, estamos administrando um site de hospedagem que provavelmente tem milhares de usuários. Inicialmente, cada usuário só carregará fotos em seu próprio perfil, mas, por padrão, não permitiremos que um veja as fotos do outro. Em condições ideais, seria adicionado um nível a mais de isolamento à autorização da chamada de cada usuário à sua API para garantir que todos solicitem apenas dados da partição deles. Entretanto, no nível do esquema, chaves de partição exclusivas são adequadas.

**Principais atributos deste componente básico**
+ A quantidade de dados lidos por qualquer usuário ou locatário só pode ser igual à quantidade total de itens na partição dele.
+ A remoção dos dados de um locatário devido ao encerramento de uma conta ou a uma solicitação de conformidade pode ser feita de forma discreta e econômica. Basta realizar uma consulta em que a chave de partição seja igual ao ID do locatário e, em seguida, executar uma operação `DeleteItem` para cada chave primária retornada.

**nota**  
Como a multilocação faz parte do conceito, é possível usar diferentes provedores de chaves de criptografia em uma única tabela para isolar dados com segurança. [AWS O SDK de criptografia de banco de dados](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/what-is-database-encryption-sdk.html) para o Amazon DynamoDB possibilita que você inclua criptografia do lado do cliente em workloads do DynamoDB. Você pode realizar a criptografia em cada atributo, o que permite criptografar valores de atributos específicos antes de armazená-los na tabela do DynamoDB e pesquisar atributos criptografados sem descriptografar o banco de dados inteiro de antemão. 

## Componente básico: índice esparso
<a name="data-modeling-blocks-sparse-index"></a>

Às vezes, um padrão de acesso exige a busca de itens que correspondam a um item raro ou recebam um status (o que exige uma resposta escalada). Em vez de consultar regularmente todo o conjunto de dados em busca desses itens, podemos nos valer do fato de os **índices secundários globais (GSI)** serem escassamente carregados de dados. Isso significa que apenas os itens na tabela base que tenham os atributos definidos no índice serão replicados no índice.

![\[Imagem mostrando uma tabela base que recebe grande quantidade de dados em estado estacionário.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SparseBaseTable.png)


![\[Imagem mostrando um índice secundário global que só recebe itens que foram escalados.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SparseGSI.png)


Neste exemplo, vemos um caso de uso de IoT em que cada dispositivo no campo relata um status regularmente. Na maioria dos relatórios, esperamos que o dispositivo informe que está tudo bem, mas às vezes pode haver uma falha e ser necessário encaminhá-la a um técnico de reparos. Para relatórios com escalonamento, o atributo `EscalatedTo` é adicionado ao item, mas não está presente de outra forma. Neste exemplo, o GSI é particionado por `EscalatedTo` e, como ele traz as chaves da tabela base, ainda podemos ver qual DeviceID relatou a falha e em que momento.

Embora no DynamoDB as leituras sejam mais baratas do que as gravações, os índices esparsos são uma ferramenta muito eficaz para casos de uso em que as instâncias de um tipo específico de item são raras mas as leituras para encontrá-las são comuns.

**Principais atributos deste componente básico**
+ Os custos de gravação e armazenamento do GSI esparso só se aplicam a itens que correspondam ao padrão de chave; portanto, o custo do GSI pode ser significativamente menor do que o de outros GSIs em que todos os itens são replicados neles. 
+ É possível também usar uma chave de classificação composta para restringir ainda mais os itens que correspondam à consulta desejada; por exemplo, um carimbo de data e hora pode ser usado para que a chave de classificação veja somente as falhas relatadas nos últimos X minutos (). (`SK > 5 minutes ago, ScanIndexForward: False`)

## Componente básico: vida útil
<a name="data-modeling-blocks-ttl"></a>

A maioria dos dados tem um tempo durante o qual se considera útil mantê-los em um datastore primário. Para lidar com o envelhecimento dos dados no DynamoDB, ele tem um atributo chamado **vida útil (TTL)**. O [TTL](TTL.md) possibilita definir um recurso específico por tabela que precisa ser monitorado em relação a itens com um carimbo de data e hora de época (que esteja no passado). Isso possibilita que você exclua registros expirados da tabela gratuitamente.

**nota**  
Se estiver usando [Global Tables versão 2019.11.21 (atual)](GlobalTables.md) das tabelas globais e também usar o recurso [Vida útil](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html), o DynamoDB replicará as exclusões do TTL em todas as tabelas de réplica. A exclusão inicial do TTL não consome capacidade de gravação na região onde o TTL expira. No entanto, a exclusão do TTL replicada para as tabelas-réplica consome capacidade de gravação replicada em cada uma das regiões de réplica e, nesse caso, se aplicam cobranças.

![\[Imagem mostrando uma tabela com mensagens de um usuário com um atributo de vida útil.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/TTL.png)


Neste exemplo, temos uma aplicação projetada para permitir que um usuário crie mensagens de curta duração. Quando se cria uma mensagem no DynamoDB, o atributo TTL é definido como uma data de sete dias no futuro pelo código da aplicação. Em aproximadamente sete dias, o DynamoDB verificará se o carimbo de data e hora de época desses itens está no passado e os excluirá.

Como as exclusões feitas pelo TTL são gratuitas, é altamente recomendável usar esse atributo para remover dados históricos da tabela. Isso reduzirá a conta geral de armazenamento a cada mês e provavelmente diminuirá os custos das leituras do usuário, pois haverá menos dados a serem recuperados pelas consultas. Embora o TTL seja habilitado em nível de tabela, cabe a você decidir para quais itens ou entidades criará um atributo TTL e definir o carimbo de data e hora de época futuro.

**Principais atributos deste componente básico**
+ As exclusões de TTL são executadas nos bastidores e não afetam a performance da tabela 
+ Embora o TTL seja um processo assíncrono que é executado a cada 6 horas, aproximadamente, a exclusão de um registro expirado pode levar mais de 48 horas. 
  + Não conte com as exclusões de TTL para casos de uso, como registros de bloqueio ou gerenciamento de estado, se houver necessidade de limpar dados obsoletos em menos de 48 horas 
+ Você pode dar um nome de atributo válido ao TTL, mas o valor deve ser numérico.

## Componente básico: vida útil para arquivamento
<a name="data-modeling-blocks-ttl-archival"></a>

Embora o TTL seja uma ferramenta eficaz para excluir dados antigos do DynamoDB, muitos casos de uso exigem que os dados sejam mantidos arquivados por um período mais longo do que o do datastore primário. Nesse caso, podemos utilizar a exclusão cronometrada de registros do TTL para enviar registros expirados a um datastore de longo prazo.

![\[Imagem mostrando uma tabela que envia um trabalho de exclusão em tempo real ao DynamoDB Streams seguido de um datastore de longo prazo.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/TTLArchive.png)


Quando uma exclusão de TTL é feita pelo DynamoDB, ela ainda é enviada ao DynamoDB Stream como um evento `Delete`. No entanto, quando a exclusão é realizada pelo TTL do DynamoDB, há um atributo `principal:dynamodb` no registro de fluxo. Usando um assinante do Lambda do DynamoDB Stream, podemos aplicar um filtro de eventos somente ao atributo da entidade principal do DynamoDB e ter certeza de que todos os registros que correspondam a esse filtro sejam enviados a um armazenamento de arquivos, como o Amazon Glacier.

**Principais atributos deste componente básico**
+  Quando as leituras de baixa latência do DynamoDB não são mais necessárias para os itens históricos, migrá-las para um serviço de armazenamento mais frio, como o Amazon Glacier, pode reduzir significativamente os custos de armazenamento e, ao mesmo tempo, atender às necessidades de conformidade de dados de seu caso de uso. 
+ Se os dados persistirem no Amazon S3, poderão ser usadas ferramentas de análise econômicas, como o Amazon Athena ou o Redshift Spectrum, para realizar análises históricas dos dados.

## Componente básico: particionamento vertical
<a name="data-modeling-blocks-vertical-partitioning"></a>

Os usuários que já conhecem um banco de dados de modelos de documentos estarão familiarizados com a ideia de armazenar todos os dados relacionados em um único documento JSON. Embora o DynamoDB seja compatível com tipos de dados JSON, ele não comporta a execução de `KeyConditions` em JSON aninhado. Como `KeyConditions` são os fatores que determinam a quantidade de dados lidos do disco e, efetivamente, quantas RCUs uma consulta consome, isso pode gerar ineficiência em grande escala. Para otimizar ainda mais as gravações e leituras do DynamoDB, recomendamos dividir as entidades individuais do documento em itens individuais do DynamoDB, técnica também chamada de **particionamento vertical**.

![\[Imagem mostrando uma grande estrutura de dados formatada como um objeto JSON aninhado.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DocumentBlob.png)


![\[Imagem mostrando uma coleção de itens em que a chave de classificação do item ajuda a manter o uso do DynamoDB otimizado.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SingleTableSchema.png)


O particionamento vertical, conforme mostrado acima, é um exemplo básico de design de tabela única em ação, mas também é possível implementá-lo em várias tabelas, se desejado. Como o DynamoDB fatura as gravações em incrementos de 1 KB, o ideal é particionar o documento de uma maneira que resulte em itens com menos de 1 KB.

**Principais atributos deste componente básico**
+ Uma hierarquia de relacionamentos de dados é mantida por meio de prefixos de chave de classificação para que seja possível reconstruir a estrutura singular do documento no lado do cliente, se necessário. 
+ É possível atualizar componentes singulares da estrutura de dados de maneira independente, o que resulta em atualizações de itens tão pequenos quanto 1 WCU. 
+ Usando a chave de classificação `BeginsWith`, a aplicação pode recuperar dados semelhantes em uma única consulta, agregando custos de leitura para reduzir o custo e latência totais.
+ Documentos grandes podem ultrapassar facilmente o limite de tamanho de item individual de 400 KB no DynamoDB, e o particionamento vertical ajuda a contornar esse limite

## Componente básico: fragmentação de gravação
<a name="data-modeling-blocks-write-sharding"></a>

Um dos poucos limites rígidos do DynamoDB é a restrição ao throughput que uma única partição física pode manter por segundo (não necessariamente uma única chave de partição). No momento, esses limites são:
+ 1.000 WCU (ou 1.000 <= 1 KB itens gravados por segundo) e 3.000 RCU (ou 3.000 <= 4 KB de leituras por segundo) *altamente consistentes* ou 
+ 6.000 leituras <= 4 KB por segundo *finais consistentes*

Caso as solicitações da tabela excedam qualquer um desses limites, um erro é enviado de volta ao SDK do cliente `ThroughputExceededException`, mais comumente chamado de controle de utilização. Os casos de uso que exigem operações de leitura além desse limite geralmente são mais bem atendidos por meio da colocação de um cache de leitura na frente do DynamoDB, mas as operações de gravação exigem um design em nível de esquema conhecido como **fragmentação de gravação**.

![\[Imagem mostrando como o DynamoDB fragmenta chaves de partição em várias partições para evitar o controle de utilização de picos no tráfego.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/WriteShardingProblem.png)


![\[Imagem mostrando como o DynamoDB fragmenta chaves de partição em várias partições para evitar o controle de utilização de picos no tráfego.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/WriteShardingSolution.png)


Para resolver esse problema, acrescentaremos um número inteiro aleatório ao final da chave de partição para cada candidato no código `UpdateItem` da aplicação. O intervalo do gerador de números inteiros aleatórios precisará ter um limite superior correspondente ou acima da quantidade esperada de gravações por segundo para determinado candidato dividido por 1.000. Para atender a 20.000 votos por segundo, teríamos rand(0,19). Agora que os dados estão armazenados em partições lógicas separadas, eles devem ser combinados novamente no momento da leitura. Como o total de votos não precisa ser em tempo real, uma função do Lambda programada para ler todas as partições de votos a cada X minutos pode realizar uma agregação ocasional para cada candidato e gravá-la de volta em um único registro de total de votos para leituras ao vivo.

**Principais atributos deste componente básico**
+ Para casos de uso com um throughput extremamente alto para determinada chave de partição que não pode ser evitada, as operações de gravação podem ser distribuídas artificialmente por várias partições do DynamoDB. 
+ Os GSIs com uma chave de partição com baixa cardinalidade também devem utilizar esse padrão, pois o controle de utilização em um GSI aplicará uma pressão contrária nas operações de gravação na tabela base.

# Pacotes de design de esquema de modelagem de dados no DynamoDB
<a name="data-modeling-schemas"></a>

Saiba mais sobre os pacotes de design de esquemas de modelagem de dados para o DynamoDB, incluindo casos de uso, padrões de acesso e designs de esquemas finais para redes sociais, perfis de jogos, gerenciamento de reclamações, pagamentos recorrentes, status de dispositivos e lojas virtuais.

![\[Imagem mostrando a relação conceitual entre os dados, os componentes abaixo deles e a base sob os componentes. Ênfase sobre a base.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignData.png)


## Pré-requisitos
<a name="data-modeling-prereqs"></a>

Antes de tentarmos criar nosso esquema para o DynamoDB, primeiro precisamos reunir alguns dados de pré-requisitos sobre o caso de uso que o esquema precisa apoiar. Diferentemente dos bancos de dados relacionais, o DynamoDB é fragmentado por padrão, o que significa que os dados permanecerão em vários servidores nos bastidores. Portanto, é importante projetar de acordo com a localidade dos dados. Precisaremos montar a seguinte lista para cada design de esquema:
+ Lista de entidades (diagrama ER)
+ Volumes e throughput previstos para cada entidade
+ Padrões de acesso que precisam ser atendidos (consultas e gravações)
+ Requisitos de retenção de dados

**Topics**
+ [Pré-requisitos](#data-modeling-prereqs)
+ [Design de esquema de rede social no DynamoDB](data-modeling-schema-social-network.md)
+ [Design de esquema de perfil de jogo no DynamoDB](data-modeling-schema-gaming-profile.md)
+ [Design do esquema do sistema de gerenciamento de reclamações no DynamoDB](data-modeling-complaint-management.md)
+ [Design de esquema de pagamentos recorrentes no DynamoDB](data-modeling-schema-recurring-payments.md)
+ [Monitoramento das atualizações de status do dispositivo no DynamoDB](data-modeling-device-status.md)
+ [Usar o DynamoDB como armazenamento de dados para uma loja virtual](data-modeling-online-shop.md)

# Design de esquema de rede social no DynamoDB
<a name="data-modeling-schema-social-network"></a>

## Caso de uso de negócios de redes sociais
<a name="data-modeling-schema-social-network-use-case"></a>

Esse caso de uso aborda o uso do DynamoDB como uma rede social. Uma rede social é um serviço on-line que permite que diferentes usuários interajam entre si. A rede social que criaremos permitirá que o usuário veja uma linha do tempo que consiste em suas publicações, seguidores, quem ele está seguindo e publicações escritas por quem ele está seguindo. Os padrões de acesso para este design de esquema são:
+ Obter informações do usuário para determinado ID de usuário 
+ Obter lista de seguidores para determinado ID de usuário
+ Obter lista de seguidores para determinado ID de usuário
+ Obter lista de seguidores para determinado ID de usuário
+ Obter a lista de usuários que curtiram a publicação de determinado PostID
+ Obter a contagem de curtidas para determinado PostID
+ Obter a linha do tempo de determinado ID de usuário

## Diagrama de relacionamento de entidades de redes sociais
<a name="data-modeling-schema-social-network-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para o design do esquema da rede social.

![\[ERD para uma aplicação de rede social que mostra entidades, como User, Post e Follower.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetworkERD.png)


## Padrões de acesso da rede social
<a name="data-modeling-schema-social-network-access-patterns"></a>

Estes são os padrões de acesso que vamos considerar para o design do esquema da rede social.
+ `getUserInfoByUserID`
+ `getFollowerListByUserID`
+ `getFollowingListByUserID`
+ `getPostListByUserID`
+ `getUserLikesByPostID`
+ `getLikeCountByPostID`
+ `getTimelineByUserID`

## Evolução do design do esquema da rede social
<a name="data-modeling-schema-social-network-design-evolution"></a>

O DynamoDB é um banco de dados NoSQL. Por isso, ele não permite que você realize uma união; isto é, uma operação que combina dados de vários bancos de dados. Os clientes que não estão familiarizados com o DynamoDB podem aplicar filosofias de design do sistema de gerenciamento de banco de dados relacional (RDBMS) (como criar uma tabela para cada entidade) ao DynamoDB quando na verdade não precisam. O objetivo do design de tabela única do DynamoDB é gravar dados em um formato pré-unido de acordo com o padrão de acesso da aplicação e, em seguida, usar imediatamente os dados sem computação adicional. Para obter mais informações, consulte [Design de tabela única versus design de várias tabelas no DynamoDB](https://aws.amazon.com/blogs/database/single-table-vs-multi-table-design-in-amazon-dynamodb/). 

Agora vamos ver como desenvolveremos nosso design de esquema para abordar todos os padrões de acesso.

**Etapa 1: abordar o padrão de acesso 1 (`getUserInfoByUserID`)**

Para receber informações de um usuário específico, precisaremos usar [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) na tabela base com uma condição de chave `PK=<userID>`. A operação de consulta permite paginar os resultados, o que pode ser útil quando um usuário tem muitos seguidores. Para obter mais informações sobre Query, consulte [Consultar tabelas no DynamoDB](Query.md). 

Em nosso exemplo, rastreamos dois tipos de dados para nosso usuário: “count” e “info”. A “contagem” de um usuário reflete quantos seguidores ele tem, quantos usuários ele está seguindo e quantas publicações ele criou. As “informações” de um usuário refletem suas informações pessoais, como seu nome.

Vemos esses dois tipos de dados representados pelos dois itens abaixo. O item que tem “count” na chave de classificação (SK) tem maior probabilidade de mudar do que o item com “info”. O DynamoDB considera o tamanho do item conforme ele aparece antes e depois da atualização, e o throughput provisionado consumido refletirá o item de tamanho maior. Mesmo se você atualizar apenas um subconjunto dos atributos do item, [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) ainda consumirá a quantidade total do throughput provisionado (o maior tamanho de item de “antes” e “depois”). Você pode obter os itens por meio de uma única operação `Query` e usar `UpdateItem` para adicionar ou subtrair atributos numéricos existentes.

![\[Resultado da operação de consulta para um usuário com ID u#12345 e os dados de contagem e informações.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork1.png)


**Etapa 2: abordar o padrão de acesso 2 (`getFollowerListByUserID`)**

Para obter uma lista dos usuários que estão seguindo determinado usuário, precisaremos utilizar `Query` na tabela base com uma condição de chave `PK=<userID>#follower`. 

![\[Resultado da operação de consulta em uma tabela para listar os seguidores do usuário com ID u#12345.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork2.png)


**Etapa 3: abordar o padrão de acesso 3 (`getFollowingListByUserID`)**

Para obter uma lista dos usuários que um usuário está seguindo, precisaremos utilizar `Query` na tabela base com uma condição de chave `PK=<userID>#following`. Depois, você pode usar uma operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) para agrupar várias solicitações e fazer o seguinte:
+ Adicionar o usuário A à lista de seguidores do usuário B e, depois, incrementar a contagem de seguidores do usuário B em um.
+ Adicionar o usuário B à lista de seguidores do usuário A e, depois, incrementar a contagem de seguidores do usuário A em um.

![\[Resultado da operação de consulta em uma tabela para listar todos os usuários que o usuário com ID u#12345 está seguindo.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork3.png)


**Etapa 4: abordar o padrão de acesso 4 (`getPostListByUserID`)**

Para obter uma lista das publicações de determinado usuário, precisaremos utilizar `Query` na tabela base com uma condição de chave `PK=<userID>#post`. Um fator importante a observar aqui é que os postIDs de um usuário devem ser incrementais: o segundo valor postID deve ser maior que o primeiro valor postID (já que os usuários querem ver suas publicações de forma ordenada). Você pode fazer isso gerando PostIDs com base em um valor de tempo, como um identificador lexicograficamente classificável universalmente exclusivo (ULID).

![\[Resultado da operação de consulta com uma condição de chave para receber uma lista de postagens criadas por um usuário específico.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork4.png)


**Etapa 5: abordar o padrão de acesso 5 (`getUserLikesByPostID`)**

Para obter uma lista dos usuários que curtiram a publicação de determinado usuário, precisaremos utilizar `Query` na tabela base com uma condição de chave `PK=<postID>#likelist`. Essa abordagem é o mesmo padrão que usamos para recuperar as listas de seguidores e seguidos nos padrões de acesso 2 (`getFollowerListByUserID`) e 3 (`getFollowingListByUserID`).

![\[Resultado da operação de consulta com uma condição de chave para receber uma lista de usuários que curtiram a postagem de um usuário específico.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork5.png)


**Etapa 6: abordar o padrão de acesso 6 (`getLikeCountByPostID`)**

Para obter uma contagem de curtidas de determinada publicação, precisaremos realizar uma operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) na tabela base com uma condição de chave `PK=<postID>#likecount`. Esse padrão de acesso pode causar problemas de controle de utilização sempre que um usuário com muitos seguidores (como uma celebridade) criar uma publicação, pois a limitação ocorre quando o throughput de uma partição excede 1.000 WCU por segundo. Esse problema não é provocado pelo DynamoDB. Ele só aparece no DynamoDB porque está no final da pilha de software.

Você deve avaliar se é realmente essencial que todos os usuários visualizem a contagem de curtidas simultaneamente ou se isso pode ocorrer gradualmente ao longo do tempo. Em geral, a contagem de curtidas de uma publicação não precisa ser 100% exata imediatamente. Você pode implementar essa estratégia colocando uma fila entre a aplicação e o DynamoDB para que as atualizações ocorram periodicamente.

![\[Resultado da operação GetItem com uma condição de chave para receber a contagem de curtidas de uma postagem específica.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork6.png)


**Etapa 7: abordar o padrão de acesso 7 (`getTimelineByUserID`)**

Para obter a linha do tempo de determinado usuário, precisaremos realizar uma operação `Query` na tabela base com uma condição de chave `PK=<userID>#timeline`. Vamos considerar uma situação em que os seguidores de um usuário precisam ver a publicação dele de forma síncrona. Toda vez que um usuário escreve uma publicação, sua lista de seguidores é lida e seu ID de usuário e postID são inseridos lentamente na chave da linha do tempo de todos os respectivos seguidores. Em seguida, quando a aplicação for iniciada, você poderá ler a chave da linha do tempo com a operação `Query` e preencher a tela da linha do tempo com uma combinação de UserID e PostID usando a operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) para qualquer item novo. Não é possível ler a linha do tempo com uma chamada de API, mas essa é uma solução mais econômica se as publicações puderem ser editadas com frequência.

Como a linha do tempo é um local que mostra as publicações recentes, precisaremos de um meio para limpar as antigas. Em vez de usar WCU para excluí-las, você pode usar o atributo [TTL](TTL.md) do DynamoDB para fazer isso gratuitamente.

![\[Resultado da operação de consulta com uma condição de chave para receber a linha do tempo de determinado usuário mostrando suas postagens recentes.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork7.png)


Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | Outras condições/filtros | 
| --- | --- | --- | --- | --- | --- | 
| getUserInfoByUserID | Tabela base | Consulta | PK=<userID> |  |  | 
| getFollowerListByUserID | Tabela base | Consulta | PK=<userID>\$1follower |  |  | 
| getFollowingListByUserID | Tabela base | Consulta | PK=<userID>\$1following |  |  | 
| getPostListByUserID | Tabela base | Consulta | PK=<userID>\$1post |  |  | 
| getUserLikesByPostID | Tabela base | Consulta | PK=<postID>\$1likelist |  |  | 
| getLikeCountByPostID | Tabela base | GetItem | PK=<postID>\$1likecount |  |  | 
| getTimelineByUserID | Tabela base | Consulta | PK=<userID>\$1timeline |  |  | 

## Esquema final da rede social
<a name="data-modeling-schema-social-network-final-schema"></a>

Veja aqui o design do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [DynamoDB Examples](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/SocialNetwork/SocialNetworkSchema.json) no GitHub.

**Tabela base:**

![\[Design do esquema final de uma tabela que contém os resultados das operações Query e GetItem anteriores.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork8.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-social-network-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Design de esquema de perfil de jogo no DynamoDB
<a name="data-modeling-schema-gaming-profile"></a>

## Caso de uso de negócios de perfil de jogo
<a name="data-modeling-schema-gaming-profile-use-case"></a>

Este caso de uso aborda o uso do DynamoDB para armazenar perfis de jogadores em um sistema de jogos. Os usuários (neste caso, os jogadores) precisam criar perfis para poderem interagir com vários jogos modernos, especialmente os on-line. Geralmente, os perfis de jogos incluem:
+ Informações básicas, como nome de usuário
+ Dados do jogo, como itens e equipamentos
+ Registros do jogo, como tarefas e atividades
+ Informações sociais, como listas de amigos

Para atender aos requisitos detalhados de acesso à consulta de dados dessa aplicação, as chaves primárias (chave de partição e chave de classificação) usarão nomes genéricos (PK e SK) para que sejam sobrecarregadas com vários tipos de valor, como veremos abaixo.

Os padrões de acesso para este design de esquema são:
+ Obter a lista de amigos de um usuário
+ Obter todas as informações de um jogador
+ Obter a lista de itens de um usuário
+ Obter um item específico da lista de itens do usuário
+ Atualizar o personagem de um usuário
+ Atualizar a contagem de itens de um usuário

O tamanho do perfil de jogo variará de acordo com o jogo. [A compactação de valores de atributos grandes](bp-use-s3-too.md) possibilita que eles se ajustem aos limites do item no DynamoDB e reduzam os custos. Nesse caso, a estratégia de gerenciamento de throughput dependeria de vários fatores, como número de jogadores, número de jogos jogados por segundo e sazonalidade da workload. Normalmente, para um jogo recém-lançado, o número de jogadores e o nível de popularidade são desconhecidos, então começaremos com o [modo de throughput sob demanda](capacity-mode.md#capacity-mode-on-demand).

## Diagrama de relacionamento de entidades de perfil de jogo
<a name="data-modeling-schema-gaming-profile-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para o design do esquema do perfil de jogo.

![\[Diagrama de ER para um perfil de jogo, mostrando relações entre entidades, como User, Game e Score.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfileERD.png)


## Padrões de acesso do perfil de jogo
<a name="data-modeling-schema-gaming-profile-access-patterns"></a>

Estes são os padrões de acesso que vamos considerar para o design do esquema da rede social.
+ `getPlayerFriends`
+ `getPlayerAllProfile`
+ `getPlayerAllItems`
+ `getPlayerSpecificItem`
+ `updateCharacterAttributes`
+ `updateItemCount`

## Evolução do design do esquema do perfil de jogo
<a name="data-modeling-schema-social-network-design-evolution"></a>

No ERD acima, podemos ver que esse é um tipo de modelagem de dados de relação de um para muitos. No DynamoDB, os modelos de dados de um para muitos podem ser organizados em coleções de itens, o que é diferente dos bancos de dados relacionais tradicionais, nos quais várias tabelas são criadas e vinculadas por meio de chaves externas. [Coleção de itens](WorkingWithItemCollections.md) é um grupo de itens que compartilham o mesmo valor de chave de partição, mas têm valores de chave de classificação diferentes. Em uma coleção, cada item tem um valor de chave de classificação exclusivo que o distingue dos demais. Com isso em mente, vamos usar o padrão a seguir para os valores `HASH` e `RANGE` referentes a cada tipo de entidade.

Primeiro, usamos nomes genéricos como `PK` e `SK` para armazenar diferentes tipos de entidade na mesma tabela e tornar o modelo preparado para o futuro. A fim de melhorar a legibilidade, podemos incluir prefixos para indicar o tipo de dados ou incluir um atributo arbitrário chamado `Entity_type` ou `Type`. No presente exemplo, usamos uma string que começa com `player` para armazenar `player_ID` como `PK`, usamos `entity name#` como prefixo de `SK` e adicionamos um atributo `Type` para indicar o tipo de entidade desse dado. Isso nos permite comportar o armazenamento de mais tipos de entidade no futuro e usar tecnologias avançadas, como sobrecarga de GSI e GSI esparso, para atender a mais padrões de acesso.

Vamos começar a implementar os padrões de acesso. Padrões de acesso como adicionar jogadores e equipamentos podem ser conseguidos por meio da operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html); portanto, podemos ignorá-los. Neste documento, vamos nos concentrar nos padrões de acesso típicos listados acima.

**Etapa 1: abordar o padrão de acesso 1 (`getPlayerFriends`)**

Abordamos o padrão de acesso 1 (`getPlayerFriends`) com esta etapa. No nosso design atual, a relação de amizade é simples e o número de amigos no jogo é pequeno. Para simplificar, usamos um tipo de dados de lista para armazenar listas de amigos (modelagem 1:1). Neste design, usamos [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) para satisfazer esse padrão de acesso. Na operação `GetItem`, fornecemos explicitamente a chave de partição e o valor da chave de classificação para obter um item específico.

No entanto, se um jogo tiver um grande número de amigos e os relacionamentos entre eles forem complexos (como amizades bidirecionais com um componente de convite e aceitação), será necessário usar uma relação de muitos para muitos para armazenar cada amigo individualmente e escalar para um tamanho ilimitado de lista de amigos. Além disso, se a mudança de amizade envolver a operação de vários itens ao mesmo tempo, as transações do DynamoDB podem ser usadas para agrupar várias ações e enviá-las como uma única operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) ou [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html) do tipo “tudo ou nada”.

![\[Diagrama de relação de um para muitos (MITM) para um perfil de jogo da entidade Friends.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile1.png)


**Etapa 2: abordar os padrões de acesso 2 (`getPlayerAllProfile`), 3 (`getPlayerAllItems`) e 4 (`getPlayerSpecificItem`)**

Abordamos os padrões de acesso 2 (`getPlayerAllProfile`), 3 (`getPlayerAllItems`) e 4 (`getPlayerSpecificItem`) com esta etapa. O que esses três padrões de acesso têm em comum é uma consulta de intervalo, que usa a operação [`Query`](Query.md). Dependendo do escopo da consulta, são usadas expressões de [condição de chave](Query.KeyConditionExpressions.md) e de [filtro](Query.FilterExpression.md), que normalmente são utilizadas no desenvolvimento prático.

Na operação de consulta, fornecemos um único valor para a chave de partição e obtemos todos os itens com esse valor de chave de partição. O padrão de acesso 2 (`getPlayerAllProfile`) é implementado dessa forma. Opcionalmente, podemos adicionar uma expressão de condição de chave de classificação, que é uma string que determina os itens a serem lidos da tabela. Para implementar o padrão de acesso 3 (`getPlayerAllItems`), adicionamos a condição de chave de classificação begins\$1with `ITEMS#`. Além disso, para simplificar o desenvolvimento do lado da aplicação, podemos usar expressões de filtro para implementar o padrão de acesso 4 (`getPlayerSpecificItem`).

Veja aqui um exemplo de pseudocódigo usando uma expressão de filtro que filtra itens da categoria `Weapon`:

```
filterExpression: "ItemType = :itemType"
expressionAttributeValues: {":itemType": "Weapon"}
```

![\[Usando a operação de consulta com uma chave de partição e condições de chave de classificação para implementar diferentes padrões de acesso.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile2.png)


**nota**  
A expressão de filtro é aplicada depois que a operação é concluída, porém antes que os resultados sejam retornados. Portanto, a operação consome a mesma quantidade de capacidade de leitura, independentemente de haver uma expressão de filtro.

Se o padrão de acesso for consultar um grande conjunto de dados e filtrar uma grande quantidade de dados para manter apenas um pequeno subconjunto de dados, a abordagem apropriada será criar a chave de partição e a chave de classificação do DynamoDB de uma maneira mais eficiente. Por exemplo, no exemplo acima para obter um determinado `ItemType`, se houvesse muitos itens para cada jogador e se consultar um determinado `ItemType` fosse um padrão de acesso típico, seria mais eficiente inserir `ItemType` em `SK` como uma chave composta. O modelo de dados ficaria assim: `ITEMS#ItemType#ItemId`.

**Etapa 3: abordar os padrões de acesso 5 (`updateCharacterAttributes`) e 6 (`updateItemCount`) **

Abordamos os padrões de acesso 5 (`updateCharacterAttributes`) e 6 (`updateItemCount`) com esta etapa. Quando o jogador precisar modificar o personagem, reduzindo a moeda ou modificando a quantidade de uma determinada arma em seus itens, por exemplo, use [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) para implementar esses padrões de acesso. Para atualizar a moeda de um jogador, mas garantir que ela nunca fique abaixo do valor mínimo, podemos adicionar uma [Exemplo de expressão de condição do DynamoDB na CLI](Expressions.ConditionExpressions.md) para reduzir o saldo somente se ele for maior ou igual ao valor mínimo. Veja aqui um exemplo de pseudocódigo:

```
UpdateExpression: "SET currency = currency - :amount"
ConditionExpression: "currency >= :minAmount"
```

![\[Usar UpdateItem com uma expressão de condição para modificar a moeda de um jogador, garantindo que ela nunca seja menor que um valor definido.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile4-Update-player-Currency.png)


Ao desenvolver com o DynamoDB e usar [contadores atômicos](WorkingWithItems.md#WorkingWithItems.AtomicCounters) para diminuir o inventário, podemos garantir a idempotência usando o bloqueio positivo. Veja aqui um exemplo de pseudocódigo para contadores atômicos:

```
UpdateExpression: "SET ItemCount = ItemCount - :incr"
expression-attribute-values: '{":incr":{"N":"1"}}'
```

![\[Usando o contador atômico para diminuir o valor do atributo ItemCount de 5 para 4.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile5-Update-Item-Count.png)


Além disso, em uma situação em que o jogador compra um item com moeda, todo o processo precisa deduzir a moeda e adicionar um item ao mesmo tempo. Podemos usar as transações do DynamoDB para agrupar várias ações e enviá-las como uma única operação tudo ou nada `TransactWriteItems` ou `TransactGetItems`. `TransactWriteItems` é uma operação de gravação síncrona e idempotente que agrupa até 100 ações de gravação em uma única operação tudo ou nada. As ações são concluídas de forma atômica para que todas sejam bem-sucedidas ou nenhuma tenha êxito. As transações ajudam a eliminar o risco de duplicação ou desaparecimento da moeda. Para obter mais informações sobre transações, consulte [Exemplo de transações do DynamoDB](transaction-example.md).

Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | Outras condições/filtros | 
| --- | --- | --- | --- | --- | --- | 
| getPlayerFriends | Tabela base | GetItem | PK=PlayerID | SK=“FRIENDS\$1playerID” |  | 
| getPlayerAllProfile | Tabela base | Consulta | PK=PlayerID |  |  | 
| getPlayerAllItems | Tabela base | Consulta | PK=PlayerID | SK begins\$1with “ITEMS\$1” |  | 
| getPlayerSpecificItem | Tabela base | Consulta | PK=PlayerID | SK begins\$1with “ITEMS\$1” | filterExpression: "ItemType = :itemType" expressionAttributeValues: \$1 ":itemType": "Weapon" \$1 | 
| updateCharacterAttributes | Tabela base | UpdateItem | PK=PlayerID | SK=“\$1METADATA\$1playerID” | UpdateExpression: "SET currency = currency - :amount" ConditionExpression: "currency >= :minAmount" | 
| updateItemCount | Tabela base | UpdateItem | PK=PlayerID | SK =“ITEMS\$1ItemID” | update-expression: "SET ItemCount = ItemCount - :incr" expression-attribute-values: '\$1":incr":\$1"N":"1"\$1\$1'  | 

## Esquema final do perfil de jogo
<a name="data-modeling-schema-gaming-profile-final-schema"></a>

Veja aqui o design do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [DynamoDB Examples](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/GamingPlayerProfiles/GamePlayerProfilesSchema.json) no GitHub.

**Tabela base:**

![\[Design do esquema final de uma tabela que contém os resultados das implementações anteriores do padrão de acesso.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile6-FinalSchema.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-gaming-profile-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Design do esquema do sistema de gerenciamento de reclamações no DynamoDB
<a name="data-modeling-complaint-management"></a>

## Caso de uso de negócios do sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-use-case"></a>

O DynamoDB é um banco de dados adequado para um caso de uso de sistema de gerenciamento de reclamações (ou central de atendimento), pois a maioria dos padrões de acesso associados a eles corresponde a pesquisas transacionais baseadas em chave-valor. Os padrões de acesso típicos nesse cenário seriam:
+ Criar e atualizar reclamações.
+ Escalar uma reclamação.
+ Criar e ler comentários sobre uma reclamação.
+ Receber todas as reclamações de um cliente.
+ Receber todos os comentários de um agente e receber todos os encaminhamentos. 

Alguns comentários podem conter anexos que descrevem a reclamação ou a solução. Embora todos esses sejam padrões de acesso de chave-valor, pode haver requisitos adicionais, como enviar notificações quando um novo comentário é adicionado a uma reclamação ou executar consultas analíticas para descobrir a distribuição da reclamação por severidade (ou performance do agente) por semana. Um requisito adicional relacionado ao gerenciamento do ciclo de vida ou à conformidade seria arquivar os dados da reclamação após três anos de registro em log da reclamação.

## Diagrama da arquitetura do sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-ad"></a>

O diagrama a seguir mostra o diagrama de arquitetura do sistema de gerenciamento de reclamações. Este diagrama mostra as diferentes integrações de AWS service (Serviço da AWS) que o sistema de gerenciamento de reclamações usa.

![\[Fluxo de trabalho combinado para atender aos requisitos não transacionais usando integrações com vários Serviços da AWS.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-1-AD.jpg)


Além dos padrões de acesso transacional de chave-valor que trataremos posteriormente na seção de modelagem de dados do DynamoDB, temos três requisitos não transacionais. O diagrama de arquitetura acima pode ser dividido nestes três fluxos de trabalho:

1. Enviar uma notificação quando um novo comentário for adicionado a uma reclamação.

1. Executar consultas analíticas em dados semanais.

1. Arquivar dados com mais de três anos.

Vamos analisar mais profundamente cada um deles.

**Enviar uma notificação quando um novo comentário for adicionado a uma reclamação**.

Podemos usar o fluxo de trabalho abaixo para cumprir esse requisito:

![\[Fluxo de trabalho para invocar funções do Lambda para enviar notificações com base nas alterações registradas pelo DynamoDB Streams.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-2-Workflow1.jpg)


[DynamoDB Streams](Streams.md) é um mecanismo de captura de dados de alterações para registrar todas as atividades de gravação em suas tabelas do DynamoDB. Você pode configurar funções do Lambda para acionar algumas ou todas essas alterações. Um [filtro de eventos](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) pode ser configurado em acionadores do Lambda para filtrar eventos que não são relevantes para o caso de uso. Nesse caso, podemos usar um filtro para acionar o Lambda somente quando um novo comentário é adicionado e enviar uma notificação aos IDs de e-mail relevantes, que podem ser obtidos no [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) ou em qualquer outro repositório de credenciais.

**Executar consultas analíticas em dados semanais**.

O DynamoDB é adequado para workloads que se concentram principalmente no processamento transacional on-line (OLTP). Quanto aos 10% a 20% restantes dos padrões de acesso com requisitos analíticos, os dados podem ser exportados para o S3 com o atributo [Exportar para o Amazon S3](S3DataExport.HowItWorks.md) sem impacto no tráfego em tempo real na tabela do DynamoDB. Veja este fluxo de trabalho abaixo:

![\[Fluxo de trabalho para invocar periodicamente uma função do Lambda para armazenar dados do DynamoDB em um bucket do Amazon S3.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-3-Workflow2.jpg)


O [Amazon EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is) pode ser usado para acionar AWS Lambda na programação: permite configurar uma expressão cron para que a invocação do Lambda ocorra periodicamente. O Lambda pode invocar a chamada de API `ExportToS3` e armazenar dados do DynamoDB no S3. Esses dados do S3 podem então ser acessados por um mecanismo SQL como o [Amazon Athena](https://docs.aws.amazon.com/athena/latest/ug/what-is) para executar consultas analíticas nos dados do DynamoDB sem afetar a workload transacional em tempo real na tabela. Um exemplo de consulta do Athena para encontrar o número de reclamações por nível de gravidade teria a aparência abaixo:

```
SELECT Item.severity.S as "Severity", COUNT(Item) as "Count"
FROM "complaint_management"."data"
WHERE NOT Item.severity.S = ''
GROUP BY Item.severity.S ;
```

Isso gera o seguinte resultado da consulta do Athena:

![\[Resultados da consulta do Athena mostrando o número de reclamações para os níveis de gravidade P3, P2 e P1.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-4-Athena.png)


**Arquivar dados com mais de três anos**.

Você pode utilizar o atributo [vida útil (TTL)](TTL.md) do DynamoDB  para excluir dados obsoletos da tabela do DynamoDB sem custo adicional (exceto no caso de réplicas de tabelas globais para a versão 2019.11.21 (atual), em que as exclusões TTL replicadas em outras regiões consomem capacidade de gravação). Esses dados aparecem e podem ser consumidos no DynamoDB Streams para serem arquivados no Amazon S3. O fluxo de trabalho referente a esse requisito é o seguinte:

![\[Fluxo de trabalho para arquivar dados antigos em um bucket do Amazon S3 usando o recurso TTL e o DynamoDB Streams.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-5-Workflow3.jpg)


## Diagrama de relacionamento de entidades do sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para o design do esquema de gerenciamento de reclamações. 

![\[Sistema de gerenciamento de reclamações ERD que mostra as entidades Cliente, Reclamação, Comentário e Atendente.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-6-ERD.jpg)


## Padrões de acesso ao sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-access-patterns"></a>

Estes são os padrões de acesso que vamos considerar para o design do esquema de gerenciamento de reclamações.

1. createComplaint

1. updateComplaint

1. updateSeveritybyComplaintID

1. getComplaintByComplaintID

1. addCommentByComplaintID

1. getAllCommentsByComplaintID

1. getLatestCommentByComplaintID

1. getAComplaintbyCustomerIDAndComplaintID

1. getAllComplaintsByCustomerID

1. escalateComplaintByComplaintID

1. getAllEscalatedComplaints

1. getEscalatedComplaintsByAgentID (ordem da mais recente para a mais antiga)

1. getCommentsByAgentID (entre duas datas)

## Evolução do design do esquema do sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-design-evolution"></a>

Como esse é um sistema de gerenciamento de reclamações, a maioria dos padrões de acesso gira em torno de uma reclamação como entidade primária. O `ComplaintID`, por ser altamente cardinal, garantirá uma distribuição uniforme dos dados nas partições subjacentes e também é o critério de pesquisa mais comum para nossos padrões de acesso identificados. Portanto, `ComplaintID` é um bom candidato à chave de partição nesse conjunto de dados.

**Etapa 1: abordar os padrões de acesso 1 (`createComplaint`), 2 (`updateComplaint`), 3 (`updateSeveritybyComplaintID`) e 4 (`getComplaintByComplaintID`) **

Podemos usar uma chave de classificação genérica chamada “metadados” (ou “AA”) para armazenar informações específicas da reclamação, como `CustomerID`, `State`, `Severity` e `CreationDate`. Usamos operações singleton com `PK=ComplaintID` e `SK=“metadata”` para fazer o seguinte:

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html), para criar uma reclamação.

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html), para atualizar a gravidade ou outros campos nos metadados da reclamação.

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html), para buscar metadados para a reclamação.

![\[Valores de chave primária, chave de classificação e atributos, como customer_id e severidade, para um item de reclamação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-7-Step1.png)


**Etapa 2: abordar o padrão de acesso 5 (`addCommentByComplaintID`)**

Esse padrão de acesso exige um modelo de relação de um para muitos entre uma reclamação e comentários sobre a reclamação. Utilizaremos a técnica [particionamento vertical](data-modeling-blocks.md#data-modeling-blocks-vertical-partitioning) aqui para usar uma chave de classificação e criar uma coleção de itens com diferentes tipos de dados. Quando observarmos os padrões de acesso 6 (`getAllCommentsByComplaintID`) e 7 (`getLatestCommentByComplaintID`), sabemos que os comentários precisarão ser classificados por hora. Também podemos receber vários comentários ao mesmo tempo para que possamos usar a técnica [chave de classificação composta](data-modeling-blocks.md#data-modeling-blocks-composite) para acrescentar tempo e `CommentID` ao atributo de chave de classificação.

Uma opção para lidar com essas possíveis colisões de comentários seria aumentar o detalhamento do carimbo de data/hora ou adicionar um número incremental como sufixo em vez de usar `Comment_ID`. Nesse caso, prefixaremos o valor da chave de classificação dos itens correspondentes aos comentários com “comm\$1” para permitir operações baseadas em intervalos.

Também precisamos garantir que o `currentState` nos metadados da reclamação reflitam o estado quando um novo comentário for adicionado. Adicionar um comentário pode indicar que a reclamação foi atribuída a um agente ou resolvida etc. Para agrupar a adição de comentários e a atualização do estado atual nos metadados da reclamação, de uma maneira “tudo ou nada”, usaremos a API [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html). O estado da tabela resultante agora tem a seguinte aparência:

![\[Tabela para armazenar uma reclamação com comentários como uma relação de um para muitos usando uma chave de classificação composta.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-8-Step2.png)


Vamos adicionar mais alguns dados na tabela, e também `ComplaintID` como um campo separado de nosso `PK`, para preparar o modelo para o futuro, caso precisemos de outros índices em `ComplaintID`. Observe também que alguns comentários podem ter anexos, os quais serão armazenados no Amazon Simple Storage Service e só terão as respectivas referências ou URLs mantidas no DynamoDB. É prática recomendada manter o banco de dados transacional o mais enxuto possível para otimizar o custo e a performance. O arquivo de dados agora é semelhante a:

![\[Tabela com os metadados da reclamação e os dados de todos os comentários associados a cada reclamação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-9-Step3.png)


**Etapa 3: abordar os padrões de acesso 6 (`getAllCommentsByComplaintID`) e 7 (`getLatestCommentByComplaintID`)**

Para obter todos os comentários de uma reclamação, podemos usar a operação [`query`](Query.md) com a condição `begins_with` na chave de classificação. Em vez de consumir capacidade adicional de leitura para ler a entrada de metadados e, depois, precisar lidar com a sobrecarga de filtrar os resultados relevantes, ter uma condição de chave de classificação como essa nos ajuda a ler apenas o que precisamos. Por exemplo, uma operação de consulta com `PK=Complaint123` e `SK` begins\$1with `comm#` exibiria o seguinte ao ignorar a entrada de metadados:

![\[Consulte o resultado da operação usando uma condição de chave de classificação que exibe somente os comentários de uma reclamação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-10-Step4.png)


Como precisamos do comentário mais recente para uma reclamação no padrão 7 (`getLatestCommentByComplaintID`), vamos usar dois parâmetros de consulta adicionais:

1. `ScanIndexForward` deve ser definido como False para receber resultados classificados em ordem decrescente.

1. `Limit` deve ser definido como 1 para receber o comentário mais recente (apenas um)..

Tal como no padrão de acesso 6 (`getAllCommentsByComplaintID`), ignoramos a entrada de metadados usando `begins_with` `comm#` como a condição da chave de classificação. Agora você pode executar o padrão de acesso 7 nesse design usando a operação de consulta com `PK=Complaint123` e `SK=begins_with comm#`, `ScanIndexForward=False` e `Limit` 1. O seguinte item direcionado será retornado como resultado:

![\[Resultado da operação de consulta usando uma condição de chave de classificação para ver o último comentário de uma reclamação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-11-Step5.png)


Vamos adicionar mais dados fictícios à tabela.

![\[Tabela com dados fictícios para ver os comentários mais recentes sobre as reclamações recebidas.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-12-Step6.png)


**Etapa 4: abordar os padrões de acesso 8 (`getAComplaintbyCustomerIDAndComplaintID`) e 9 (`getAllComplaintsByCustomerID`)**

Os padrões de acesso 8 (`getAComplaintbyCustomerIDAndComplaintID`) e 9 (`getAllComplaintsByCustomerID`) introduzem um novo critério de pesquisa: `CustomerID`. Buscá-lo na tabela existente exige uma [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) cara, pois é necessário ler todos os dados e, depois, filtrar os itens relevantes para o `CustomerID` em questão. Podemos tornar essa pesquisa mais eficiente criando um [índice secundário global (GSI)](GSI.md) com `CustomerID` como a chave de partição. Tendo em mente a relação de um para muitos entre o cliente e as reclamações, bem como o padrão de acesso 9 (`getAllComplaintsByCustomerID`), `ComplaintID` seria o candidato certo para a chave de classificação.

Os dados no GSI ficariam assim:

![\[GSI com um modelo de relação de um para muitos para ver todas as reclamações de um CustomerID específico.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-13-Step4-GSI.png)


 Um exemplo de consulta nesse GSI para o padrão de acesso 8 (`getAComplaintbyCustomerIDAndComplaintID`) seria: `customer_id=custXYZ`, `sort key=Complaint1321`. O resultado seria:

![\[Resultado da operação de consulta em um GSI para ver dados de uma reclamação específica de determinado cliente.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-14-Step4-8.png)


Para receber todas as reclamações de um cliente sobre o padrão de acesso 9 (`getAllComplaintsByCustomerID`), a consulta no GSI seria: `customer_id=custXYZ` como a condição da chave de partição. O resultado seria:

![\[Resultado da operação de consulta usando uma condição de chave de partição para ver todas as reclamações de determinado cliente.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-15-Step4-9.png)


**Etapa 5: abordar o padrão de acesso 10 (`escalateComplaintByComplaintID`)**

Esse acesso apresenta o aspecto de encaminhamento. Para encaminhar uma reclamação, podemos usar `UpdateItem` para adicionar atributos como `escalated_to` e `escalation_time` ao item de metadados da reclamação existente. O DynamoDB fornece um design de esquema flexível, o que significa que um conjunto de atributos que não são de chave pode ser uniforme ou distinto em diferentes itens. Veja o seguinte exemplo:

`UpdateItem with PK=Complaint1444, SK=metadata`

![\[Resultado da atualização dos metadados da reclamação usando a operação da API UpdateItem.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-16-Step5.png)


**Etapa 6: abordar os padrões de acesso 11 (`getAllEscalatedComplaints`) e 12 (`getEscalatedComplaintsByAgentID`)**

Espera-se que apenas algumas reclamações sejam encaminhadas de todo o conjunto de dados. Portanto, criar um índice sobre os atributos relacionados ao encaminhamento resultaria em pesquisas eficientes e em um armazenamento GSI econômico. Podemos fazer isso utilizando a técnica [índice esparso](data-modeling-blocks.md#data-modeling-blocks-sparse-index). O GSI com uma chave de partição como `escalated_to` e uma chave de classificação como `escalation_time` ficaria desta forma:

![\[Design de GSI usando atributos relacionados à escalação, escalated_to e escalation_time.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-17-Step6.png)


Para obter todas as reclamações encaminhadas ao padrão de acesso 11 (`getAllEscalatedComplaints`), nós simplesmente verificamos esse GSI. Observe que essa verificação será eficiente e econômica devido ao tamanho do GSI. Para receber reclamações encaminhadas a um agente específico [padrão de acesso 12 (`getEscalatedComplaintsByAgentID`)], a chave de partição seria `escalated_to=agentID`, e definimos `ScanIndexForward` como `False` para classificação do mais novo para o mais antigo.

**Etapa 7: abordar o padrão de acesso 13 (`getCommentsByAgentID`)**

Para o último padrão de acesso, precisamos pesquisar uma nova dimensão: `AgentID`. Também precisamos de uma classificação baseada em tempo para ler os comentários entre duas datas. Portanto, criamos um GSI com `agent_id` como a chave de partição e `comm_date` como a chave de classificação. Os dados nesse GSI terão a seguinte aparência:

![\[Design de GSI para pesquisar comentários de determinado atendente classificados pela data do comentário.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-18.png)


Um exemplo de consulta sobre esse GSI seria `partition key agentID=AgentA` e `sort key=comm_date between (2023-04-30T12:30:00, 2023-05-01T09:00:00)`, cujo resultado é:

![\[Resultado da consulta usando uma chave de partição e uma chave de classificação em um GSI.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-19.png)


Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | Outras condições/filtros | 
| --- | --- | --- | --- | --- | --- | 
| createComplaint | Tabela base | PutItem | PK=complaint\$1id | SK=metadata |  | 
| updateComplaint | Tabela base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| updateSeveritybyComplaintID | Tabela base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| getComplaintByComplaintID | Tabela base | GetItem | PK=complaint\$1id | SK=metadata |  | 
| addCommentByComplaintID | Tabela base | TransactWriteItems | PK=complaint\$1id | SK=metadata, SK=comm\$1comm\$1date\$1comm\$1id |  | 
| getAllCommentsByComplaintID | Tabela base | Consulta | PK=complaint\$1id | SK begins\$1with "comm\$1" |  | 
| getLatestCommentByComplaintID | Tabela base | Consulta | PK=complaint\$1id | SK begins\$1with "comm\$1" | scan\$1index\$1forward=False, Limit 1 | 
| getAComplaintbyCustomerIDAndComplaintID | Customer\$1complaint\$1GSI | Consulta | customer\$1id=customer\$1id | complaint\$1id = complaint\$1id |  | 
| getAllComplaintsByCustomerID | Customer\$1complaint\$1GSI | Consulta | customer\$1id=customer\$1id | N/D |  | 
| escalateComplaintByComplaintID | Tabela base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| getAllEscalatedComplaints | Escalations\$1GSI | Verificar | N/D | N/D |  | 
| getEscalatedComplaintsByAgentID (ordem da mais recente para a mais antiga) | Escalations\$1GSI | Consulta | escalated\$1to=agent\$1id | N/D | scan\$1index\$1forward=False | 
| getCommentsByAgentID (entre duas datas) | Agents\$1Comments\$1GSI | Consulta | agent\$1id=agent\$1id | SK entre (data1, data2) |  | 

## Esquema final do sistema de gerenciamento de reclamações
<a name="data-modeling-schema-complaint-management-final-schema"></a>

Veja aqui os designs do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [DynamoDB Examples](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/ComplainManagement/ComplaintManagementSchema.json) no GitHub.

**Tabela base**

![\[Design de tabela base com metadados de reclamação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-20-Complaint_management_system.png)


**Customer\$1Complaint\$1GSI**

![\[Design de GSI mostrando reclamações de determinado cliente.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-21-Customer_Complaint_GSI.png)


**Escalations\$1GSI**

![\[Design de GSI mostrando atributos relacionados ao encaminhamento.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-22-Escalations_GSI.png)


**Agents\$1Comments\$1GSI**

![\[Design de GSI mostrando comentários feitos por um atendente específico.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-23-Comments_GSI.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-complaint-management-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Design de esquema de pagamentos recorrentes no DynamoDB
<a name="data-modeling-schema-recurring-payments"></a>

## Caso de uso de negócios de pagamentos recorrentes
<a name="data-modeling-schema-recurring-payments-use-case"></a>

Esse caso de uso fala sobre o uso do DynamoDB para implementar um sistema de pagamentos recorrentes. O modelo de dados tem as seguintes entidades: *contas*, *assinaturas* e *recibos*. Os detalhes do nosso caso de uso são os seguintes:
+ Cada *conta* pode ter várias *assinaturas*.
+ A *assinatura* tem uma `NextPaymentDate` quando o próximo pagamento precisar ser processado e uma `NextReminderDate` quando um lembrete por e-mail é enviado ao cliente.
+ Há um item para a *assinatura* que é armazenado e atualizado quando o pagamento é processado (o tamanho médio do item é de cerca de 1 KB e o throughput depende do número de *contas* e *assinaturas*).
+ O processador de *pagamentos* também criará um *recibo* como parte do processo, que é armazenado na tabela e está definido para expirar após um período usando um atributo [TTL](TTL.md).

## Diagrama de relacionamento de entidades de pagamentos recorrentes
<a name="data-modeling-schema-recurring-payments-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para o design do esquema de pagamentos recorrentes.

![\[ERD do sistema de pagamentos recorrentes mostrando entidades: Account, Subscription e Receipt.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-1-ERD.png)


## Padrões de acesso recorrentes do sistema de pagamentos recorrentes
<a name="data-modeling-schema-recurring-payments-access-patterns"></a>

Estes são os padrões de acesso que vamos considerar para o design de esquema do sistema de pagamentos recorrentes.

1. `createSubscription`

1. `createReceipt`

1. `updateSubscription`

1. `getDueRemindersByDate`

1. `getDuePaymentsByDate`

1. `getSubscriptionsByAccount`

1. `getReceiptsByAccount`

## Design de esquema de pagamentos recorrentes
<a name="data-modeling-schema-recurring-payments-design-evolution"></a>

Os nomes genéricos `PK` e `SK` são usados para atributos de chave com o objetivo de permitir o armazenamento de diferentes tipos de entidade na mesma tabela, como entidades de conta, assinatura e recibo. O usuário primeiro cria uma assinatura, na qual ele concorda em pagar uma quantia no mesmo dia de cada mês em troca de um produto. Ele pode escolher em qual dia do mês processar o pagamento. Também há um lembrete que será enviado antes do processamento do pagamento. A aplicação funciona com dois trabalhos em lote que são executados todos os dias: um trabalho em lote envia lembretes de vencimento naquele dia e o outro processa todos os pagamentos devidos naquele dia.

**Etapa 1: abordar o padrão de acesso 1 (`createSubscription`)**

O padrão de acesso 1 (`createSubscription`) é usado para criar inicialmente a assinatura, e os detalhes, incluindo `SKU`, `NextPaymentDate`, `NextReminderDate` e `PaymentDetails`, são definidos. Essa etapa mostra o estado da tabela para uma única conta com uma única assinatura. Pode haver várias assinaturas na coleção de itens, então essa é uma relação de um para muitos.

![\[Design de tabela mostrando os detalhes da assinatura de uma conta.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-2-Step1.png)


**Etapa 2: abordar os padrões de acesso 2 (`createReceipt`) e 3 (`updateSubscription`)**

O padrão de acesso 2 (`createReceipt`) é usado para criar o item de recibo. Depois que o pagamento for processado a cada mês, o processador de pagamentos enviará um recibo de volta à tabela base. Pode haver vários recibos na coleção de itens, então essa é uma relação de um para muitos. O processador de pagamentos também atualizará o item de assinatura [padrão de acesso 3 (`updateSubscription`)] para atualizar para `NextReminderDate` ou `NextPaymentDate` para o próximo mês.

![\[Detalhes do recibo e atualização do item da assinatura para mostrar a próxima data do lembrete de assinatura.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-3-Step2.png)


**Etapa 3: abordar o padrão de acesso 4 (`getDueRemindersByDate`)**

A aplicação processa lembretes para o pagamento em lotes para o dia atual. Portanto, a aplicação precisa acessar as assinaturas em uma dimensão diferente: data, em vez de conta. Esse é um bom caso de uso para um [índice secundário global (GSI)](GSI.md). Nesta etapa, adicionamos o índice `GSI-1`, que usa `NextReminderDate` como a chave de partição do GSI. Não precisamos replicar todos os itens. Esse GSI é um [índice esparso](data-modeling-blocks.md#data-modeling-blocks-sparse-index), e os itens de recibo não são replicados. Também não precisamos projetar todos os atributos, apenas incluir um subconjunto dos atributos. A imagem abaixo mostra o esquema de `GSI-1` e fornece as informações necessárias para que a aplicação envie o e-mail de lembrete.

![\[Esquema do GSI-1 com detalhes, como endereço de e-mail, dos quais a aplicação precisa para enviar um e-mail de lembrete.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-4-Step3.png)


**Etapa 4: abordar o padrão de acesso 5 (`getDuePaymentsByDate`)**

A aplicação processa os pagamentos em lotes para o dia atual da mesma forma que faz para lembretes. Nesta etapa, adicionamos `GSI-2`, e ela usa a `NextPaymentDate` como a chave de partição do GSI. Não precisamos replicar todos os itens. Esse GSI é um índice esparso, e os itens de recibo não são replicados. A imagem abaixo mostra o esquema de `GSI-2`.

![\[Esquema do GSI-2 com detalhes para processar pagamentos. NextPaymentDate é a chave de partição para GSI-2.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-5-Step4.png)


**Etapa 5: abordar os padrões de acesso 6 (`getSubscriptionsByAccount`) e 7 (`getReceiptsByAccount`)**

A aplicação pode recuperar todas as assinaturas de uma conta usando uma [consulta](Query.md) na tabela base que tem como alvo o identificador da conta (o `PK`) e usa o operador de intervalo para obter todos os itens em que o `SK` começa com “SUB\$1”. A aplicação também pode usar a mesma estrutura de consulta para recuperar todos os recibos usando um operador de intervalo e obter todos os itens em que o `SK` começa com “REC\$1”. Isso nos permite cumprir os padrões de acesso 6 (`getSubscriptionsByAccount`) e 7 (`getReceiptsByAccount`). A aplicação usa esses padrões de acesso para que o usuário possa ver suas assinaturas atuais e os recibos anteriores dos últimos seis meses. Não há nenhuma alteração no esquema da tabela nesta etapa e podemos ver abaixo como consideramos apenas os itens de assinatura no padrão de acesso 6 (`getSubscriptionsByAccount`).

![\[Resultado da operação de consulta na tabela base. Mostra a assinatura de uma conta específica.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-6-Step5.png)


Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | 
| --- | --- | --- | --- | --- | 
| createSubscription | Tabela base | PutItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| createReceipt | Tabela base | PutItem | ACC\$1account\$1id | REC\$1<RecieptDate>\$1SKU<SKUID> | 
| updateSubscription | Tabela base | UpdateItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| getDueRemindersByDate | GSI-1 | Consulta | <NextReminderDate> |  | 
| getDuePaymentsByDate | GSI-2 | Consulta | <NextPaymentDate> |  | 
| getSubscriptionsByAccount | Tabela base | Consulta | ACC\$1account\$1id | SK begins\$1with “SUB\$1” | 
| getReceiptsByAccount | Tabela base | Consulta | ACC\$1account\$1id | SK begins\$1with “REC\$1” | 

## Esquema final de pagamentos recorrentes
<a name="data-modeling-schema-recurring-payments-final-schema"></a>

Veja aqui os designs do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [DynamoDB Examples](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/ReocurringPayments/ReocurringPaymentsSchema.json) no GitHub.

**Tabela base**

![\[Design de tabela base mostrando as informações da conta e os respectivos detalhes de assinatura e recebimento.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-7-Base.png)


**GSI-1**

![\[Esquema do GSI-1 com detalhes da assinatura, como endereço de e-mail e NextPaymentDate.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-8-GSI1.png)


**GSI-2**

![\[Esquema do GSI-2 com detalhes de pagamento, como PaymentAmount e PaymentDay.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-9-GSI2.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-recurring-payments-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Monitoramento das atualizações de status do dispositivo no DynamoDB
<a name="data-modeling-device-status"></a>

Esse caso de uso aborda o uso do DynamoDB para monitorar atualizações de status de dispositivos (ou alterações no estado dos dispositivos) no DynamoDB.

## Caso de uso
<a name="data-modeling-schema-device-status-use-case"></a>

Em casos de uso de IoT (uma fábrica inteligente, por exemplo), muitos dispositivos precisam ser monitorados pelos operadores e eles enviam periodicamente seus status ou logs para um sistema de monitoramento. Quando há um problema com um dispositivo, o status dele muda de *normal* para *aviso*. Existem diferentes níveis ou status de log, dependendo da gravidade e do tipo de comportamento anormal no dispositivo. O sistema então designa um operador para verificar o dispositivo e ele pode encaminhar o problema ao supervisor, se necessário.

Alguns padrões de acesso típicos desse sistema incluem:
+ Criar entrada de log para um dispositivo
+ Obter todos os logs de um estado específico do dispositivo, mostrando primeiro os logs mais recentes
+ Obter todos os logs de determinado operador entre duas datas
+ Obter todos os logs encaminhados a determinado supervisor
+ Obter todos os logs encaminhados com um estado de dispositivo específico para determinado supervisor
+ Obter todos os logs encaminhados com um estado de dispositivo específico para determinado supervisor em uma data específica

## Diagrama de relacionamento de entidades
<a name="data-modeling-schema-device-status-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para monitorar atualizações de status de dispositivos.

![\[ERD de atualizações de status de dispositivos. Mostra as entidades: Device e Operator.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-1-ERD.jpg)


## Padrões de acesso
<a name="data-modeling-schema-device-status-access-patterns"></a>

Esses são os padrões de acesso que vamos considerar para monitorar atualizações de status de dispositivos.

1. `createLogEntryForSpecificDevice`

1. `getLogsForSpecificDevice`

1. `getWarningLogsForSpecificDevice`

1. `getLogsForOperatorBetweenTwoDates`

1. `getEscalatedLogsForSupervisor`

1. `getEscalatedLogsWithSpecificStatusForSupervisor`

1. `getEscalatedLogsWithSpecificStatusForSupervisorForDate`

## Evolução do design do esquema
<a name="data-modeling-schema-device-status-design-evolution"></a>

**Etapa 1: abordar os padrões de acesso 1 (`createLogEntryForSpecificDevice`) e 2 (`getLogsForSpecificDevice`)**

A unidade de escala de um sistema de rastreamento de dispositivos seriam dispositivos individuais. Nesse sistema, um `deviceID` identifica de forma exclusiva um dispositivo. Isso tornar `deviceID` um bom candidato para a chave de partição. Cada dispositivo envia informações ao sistema de rastreamento periodicamente (digamos, a cada cinco minutos, mais ou menos). Essa ordem torna a data um critério lógico de classificação e, portanto, a chave de classificação. Os dados de amostra, nesse caso, ficariam mais ou menos assim:

![\[Tabela para armazenar o status de vários dispositivos. DeviceID é a chave primária e a data de atualização de status é a chave de classificação.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-2-Step1.png)


Para buscar entradas de log para um dispositivo específico, podemos realizar uma operação de [consulta](Query.md) com a chave de partição `DeviceID="d#12345"`.

**Etapa 2: abordar o padrão de acesso 3 (`getWarningLogsForSpecificDevice`)**

Como `State` é um atributo não chave, abordar o padrão de acesso 3 com o esquema atual exigiria uma [expressão de filtro](Query.FilterExpression.md). No DynamoDB, as expressões de filtro são aplicadas depois que os dados são lidos usando expressões de condição de chave. Por exemplo, se fôssemos obter os logs de aviso para `d#12345`, a operação de consulta com a chave de partição `DeviceID="d#12345"` leria quatro itens da tabela acima e, depois, filtraria o único item sem o status *aviso*. Essa abordagem não é eficiente em grande escala. Uma expressão de filtro pode ser uma boa maneira de excluir itens que são consultados se a proporção de itens excluídos for baixa ou se a consulta for realizada com pouca frequência. No entanto, nos casos em que muitos itens são recuperados de uma tabela e a maioria dos itens é excluída após a filtragem, podemos continuar desenvolvendo nosso design de tabela para que funcione com maior eficiência.

Vamos mudar a forma de lidar com esse padrão de acesso usando [chaves de classificação compostas](data-modeling-blocks.md#data-modeling-blocks-composite). É possível importar dados de amostra do [DeviceStateLog\$13.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_3.json), onde a chave de classificação é alterada para `State#Date`. Essa chave de classificação é a composição dos atributos `State`, `#` e `Date`. Nesse exemplo, `#` é usado como um delimitador. Os dados agora ficam mais ou menos assim: 

![\[Dados de atualização de status do dispositivo, d #12345, recebidos com a chave de classificação composta State#Date.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-3-Step2.png)


Para obter somente logs de aviso de um dispositivo, a consulta se torna mais direcionada com esse esquema. A condição de chave para a consulta usa a chave de partição `DeviceID="d#12345"` e a chave de classificação `State#Date begins_with “WARNING”`. Essa consulta lerá somente os três itens relevantes com o estado *aviso*.

**Etapa 3: abordar o padrão de acesso 4 (`getLogsForOperatorBetweenTwoDates`)**

É possível importar [DeviceStateLog\$14.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_4.json), onde o atributo `Operator` foi adicionado à tabela `DeviceStateLog` com dados de exemplo.

![\[Design de tabela DeviceStateLog com o atributo Operator para receber os logs de um operador entre datas específicas.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-4-Step3.png)


Como no momento `Operator` não é uma chave de partição, não há como realizar uma pesquisa direta de chave-valor nessa tabela com base em `OperatorID`. Precisaremos criar uma [coleção de itens](WorkingWithItemCollections.md) com um índice secundário global em `OperatorID`. O padrão de acesso requer uma pesquisa com base em datas, então Data é o atributo da chave de classificação do [índice secundário global (GSI)](GSI.md). É assim que o GSI se parece agora:

![\[Design de GSI com OperatorID e Date como chave de partição e chave de classificação para receber logs de um operador específico.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-5-Step3.png)


Para o padrão de acesso 4 (`getLogsForOperatorBetweenTwoDates`), é possível consultar esse GSI com a chave de partição `OperatorID=Liz` e a chave de classificação `Date` entre `2020-04-11T05:58:00` e `2020-04-24T14:50:00`.

![\[Consultar no GSI usando OperatorID e Date para receber logs de um operador entre duas datas.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-6-GSI1_1.png)


**Etapa 4: abordar os padrões de acesso 5 (`getEscalatedLogsForSupervisor`), 6 (`getEscalatedLogsWithSpecificStatusForSupervisor`) e 7 (`getEscalatedLogsWithSpecificStatusForSupervisorForDate`)**

Usaremos um [índice esparso](data-modeling-blocks.md#data-modeling-blocks-sparse-index) para abordar esses padrões de acesso.

Os índices secundários globais são esparsos por padrão; portanto, somente os itens na tabela base que contêm atributos de chave primária do índice realmente aparecerão no índice. Essa é outra forma de excluir itens que não são relevantes para o padrão de acesso que está sendo modelado.

É possível importar [DeviceStateLog\$16.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_6.json), onde o atributo `EscalatedTo` foi adicionado à tabela `DeviceStateLog` com dados de exemplo. Conforme mencionado anteriormente, nem todos os logs são encaminhados para um supervisor.

![\[Design de GSI com o atributo EscalatedTo para receber todos os logs encaminhados a um supervisor.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-7-Step4.png)


Agora você pode criar um novo GSI em que `EscalatedTo` é a chave de partição e `State#Date` é a chave de classificação. Observe que somente itens que têm ambos os atributos `EscalatedTo` e `State#Date` aparecem no índice.

![\[Design de GSI para receber todos os itens com os atributos EscalatedTo e State#Date.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-8-Step4.png)


O restante dos padrões de acesso está resumido da seguinte forma:

    Para o padrão de acesso 5 (getEscalatedLogsForSupervisor), você pode realizar uma consulta no GSI de encaminhamentos com a chave de partição EscalatedTo=“Sara”   Para o padrão de acesso 6 (getEscalatedLogsWithSpecificStatusForSupervisor), você pode realizar uma consulta no GSI de encaminhamentos com a chave de partição EscalatedTo=“Sara” e a chave de classificação State\$1Date begins\$1with “WARNING”    Para o padrão de acesso 7 (getEscalatedLogsWithSpecificStatusForSupervisorForDate), você pode realizar uma consulta no GSI de encaminhamentos com a chave de partição EscalatedTo=“Sara” e a chave de classificação State\$1Date begins\$1with “WARNING4\$12020-04-27”    

Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | Outras condições/filtros | 
| --- | --- | --- | --- | --- | --- | 
| createLogEntryForSpecificDevice | Tabela base | PutItem | DeviceID=deviceId | State\$1Date=state\$1date |  | 
| getLogsForSpecificDevice | Tabela base | Consulta | DeviceID=deviceId | State\$1Date begins\$1with "state1\$1" | ScanIndexForward = False | 
| getWarningLogsForSpecificDevice | Tabela base | Consulta | DeviceID=deviceId | State\$1Date begins\$1with "WARNING" |  | 
| getLogsForOperatorBetweenTwoDates | GSI-1 | Consulta | Operator=operatorName | Data entre date1 e date2 |  | 
| getEscalatedLogsForSupervisor | GSI-2 | Consulta | EscalatedTo=supervisorName |  |  | 
| getEscalatedLogsWithSpecificStatusForSupervisor | GSI-2 | Consulta | EscalatedTo=supervisorName | State\$1Date begins\$1with "state1\$1" |  | 
| getEscalatedLogsWithSpecificStatusForSupervisorForDate | GSI-2 | Consulta | EscalatedTo=supervisorName | State\$1Date begins\$1with "state1\$1date1" |  | 

## Esquema final
<a name="data-modeling-schema-device-status-final-schema"></a>

Veja aqui os designs do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [DynamoDB Examples](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/schema_design/SchemaExamples) no GitHub.

**Tabela base**

![\[Design de tabela base com metadados de status do dispositivo, como ID do dispositivo, Estado e Data.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-9-Table.png)


**GSI-1**

![\[Design de GSI-1. Ele mostra a chave primária e os atributos: DeviceID, State#Date e State.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-10-GSI1.png)


**GSI-2**

![\[Design de GSI-2. Ele mostra a chave primária e os atributos: DeviceID, Operator, Date e State.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-11-GSI2.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-device-status-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Usar o DynamoDB como armazenamento de dados para uma loja virtual
<a name="data-modeling-online-shop"></a>

Esse caso de uso trata do uso do DynamoDB como armazenamento de dados para uma loja on-line (ou loja eletrônica).

## Caso de uso
<a name="data-modeling-schema-online-shop"></a>

Uma loja on-line permite que os usuários naveguem por diferentes produtos e, em algum momento, os comprem. Com base na fatura gerada, o cliente pode pagar usando um código de desconto ou vale-presente e depois pagar o valor restante com um cartão de crédito. Os produtos adquiridos serão retirados de um dos vários armazéns e enviados ao endereço fornecido. Os padrões de acesso típicos para uma loja on-line incluem:
+ Obter cliente para determinado customerId
+ Obter produto para determinado productId
+ Obter armazém para determinado warehouseId
+ Obter um inventário de produtos para todos os armazéns por meio de um productId
+ Obter pedido para determinado orderId
+ Obter todos os produtos de determinado orderId
+ Obter fatura para determinado orderId
+ Obter todos os envios para determinado orderId
+ Obter todos os pedidos de determinado productId em determinado intervalo de datas
+ Obter fatura para determinado invoiceId
+ Obter todos os pagamentos para determinado invoiceId
+ Obter detalhes de envio para determinado shipmentId
+ Obter todos os envios para determinado warehouseId
+ Obter o inventário de todos os produtos para determinado warehouseId
+ Obter todas as faturas para determinado customerId em um intervalo de datas específico
+ Obter todos os produtos encomendados por determinado customerId em um intervalo de datas específico

## Diagrama de relacionamento de entidades
<a name="data-modeling-schema-online-shop-erd"></a>

Este é o diagrama de relacionamento de entidades (ERD) que usaremos para modelar o DynamoDB como um armazenamento de dados de uma loja on-line.

![\[ERD para o modelo de dados de uma loja on-line com entidades, como Product, Order, Payment e Customer.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-1-ERD.png)


## Padrões de acesso
<a name="data-modeling-schema-online-shop-access-patterns"></a>

Este é o padrão de acesso que consideraremos ao usar o DynamoDB como um armazenamento de dados de uma loja on-line.

1. `getCustomerByCustomerId`

1. `getProductByProductId`

1. `getWarehouseByWarehouseId`

1. `getProductInventoryByProductId`

1. `getOrderDetailsByOrderId`

1. `getProductByOrderId`

1. `getInvoiceByOrderId`

1. `getShipmentByOrderId`

1. `getOrderByProductIdForDateRange`

1. `getInvoiceByInvoiceId`

1. `getPaymentByInvoiceId`

1. `getShipmentDetailsByShipmentId`

1. `getShipmentByWarehouseId`

1. `getProductInventoryByWarehouseId`

1. `getInvoiceByCustomerIdForDateRange`

1. `getProductsByCustomerIdForDateRange`

## Evolução do design do esquema
<a name="data-modeling-schema-online-shop-design-evolution"></a>

Usando [NoSQL Workbench para DynamoDB](workbench.md), importe [AnOnlineShop\$11.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_1.json) para criar um modelo de dados chamado `AnOnlineShop` e uma tabela chamada `OnlineShop`. Observe que usamos os nomes genéricos `PK` e `SK` para a chave de partição e a chave de classificação. Essa é uma prática usada para armazenar diferentes tipos de entidade na mesma tabela.

**Etapa 1: abordar o padrão de acesso 1 (`getCustomerByCustomerId`)**

Importe [AnOnlineShop\$12.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_2.json) para lidar com o padrão de acesso 1 (`getCustomerByCustomerId`). Algumas entidades não têm relacionamentos com outras, então usaremos o mesmo valor de `PK` e `SK` para elas. Nos dados de exemplo, observe que as chaves usam um prefixo `c#` a fim de distinguir o `customerId` de outras entidades que serão adicionadas posteriormente. Essa prática também é repetida para outras entidades. 

Para abordar esse padrão de acesso, pode ser usada uma operação [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) com `PK=customerId` e `SK=customerId`.

**Etapa 2: abordar o padrão de acesso 2 (`getProductByProductId`)**

Importe [AnOnlineShop\$13.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_3.json) para abordar o padrão de acesso 2 (`getProductByProductId`) para a entidade `product`. As entidades do produto têm `p#` como prefixo e o mesmo atributo de chave de classificação foi usado para armazenar `customerID`, bem como `productID`. A nomenclatura genérica e o [particionamento vertical](data-modeling-blocks.md#data-modeling-blocks-vertical-partitioning) nos permite criar essas coleções de itens para um design de tabela única eficaz. 

Para abordar esse padrão de acesso, pode ser usada uma operação `GetItem` com `PK=productId` e `SK=productId`.

**Etapa 3: abordar o padrão de acesso 3 (`getWarehouseByWarehouseId`)**

Importe [AnOnlineShop\$14.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_4.json) para abordar o padrão de acesso 3 (`getWarehouseByWarehouseId`) para a entidade `warehouse`. No momento, temos as entidades `customer`, `product` e `warehouse` adicionadas à mesma tabela. Elas são diferenciadas usando prefixos e o atributo `EntityType`. Um atributo de tipo (ou nomenclatura de prefixo) melhora a legibilidade do modelo. A legibilidade seria afetada se simplesmente armazenássemos IDs alfanuméricos para entidades diferentes no mesmo atributo. Seria difícil diferenciar uma entidade da outra na ausência desses identificadores. 

Para abordar esse padrão de acesso, pode ser usada uma operação `GetItem` com `PK=warehouseId` e `SK=warehouseId`.

**Tabela base:**

![\[Design de tabela do DynamoDB com prefixos e entityType para receber dados do warehouse por meio do ID.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-2-Step3.png)


**Etapa 4: abordar o padrão de acesso 4 (`getProductInventoryByProductId`)**

Importe [AnOnlineShop\$15.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_5.json) para abordar o padrão de acesso 4 (`getProductInventoryByProductId`). A entidade `warehouseItem` é usada para acompanhar o número de produtos em cada armazém. Esse item normalmente é atualizado quando um produto é adicionado ou removido de um depósito. Conforme visto no ERD, há uma relação de muitos para muitos entre `product` e `warehouse`. Aqui, a relação de um para muitos de `product` para `warehouse` é modelada como `warehouseItem`. Posteriormente, a relação de um para muitos de `warehouse` para `product` também será modelada. 

O padrão de acesso 4 pode ser abordado com uma consulta em `PK=ProductId` e `SK begins_with “w#“`. 

Para obter mais informações sobre `begins_with()` e outras expressões que podem ser aplicadas para chaves de classificação, consulte [Expressões de condição de chave](Query.KeyConditionExpressions.md).

**Tabela base:**

![\[Design de tabela para consultar ProductID e warehouseId para rastrear o estoque de produtos em determinado depósito.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-3-Step4.png)


**Etapa 5: abordar os padrões de acesso 5 (`getOrderDetailsByOrderId`) e 6 (`getProductByOrderId`)**

Adicione um mais alguns itens `customer`, `product` e `warehouse` à tabela importando [AnOnlineShop\$16.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_6.json). Depois, importe [AnOnlineShop\$17.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_7.json) para criar uma coleção de itens para `order` que possa abordar os padrões de acesso 5 (`getOrderDetailsByOrderId`) e 6 (`getProductByOrderId`). Você pode ver a relação de um para muitos entre `order` e `product` modelada como entidades orderItem. 

Para abordar o padrão de acesso 5 (`getOrderDetailsByOrderId`), consulte a tabela com `PK=orderId`. Isso fornecerá todas as informações sobre o pedido, incluindo `customerId` e produtos encomendados.

**Tabela base:**

![\[Design de tabela para consulta usando orderId para receber informações sobre todos os produtos pedidos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-4-Step5.png)


Para abordar o padrão de acesso 6 (`getProductByOrderId`), precisamos ler os produtos somente em um `order`. Consulte a tabela com `PK=orderId` e `SK begins_with “p#”` para fazer isso.

**Tabela base:**

![\[Design de tabela para consulta usando orderId e productId para receber produtos em um pedido.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-5-Step5.png)


**Etapa 6: abordar o padrão de acesso 7 (`getInvoiceByOrderId`)**

Importe [AnOnlineShop\$18.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_8.json) para adicionar uma entidade `invoice` à coleção de itens de *pedido* e lidar com o padrão de acesso 7 (`getInvoiceByOrderId`). Para abordar esse padrão de acesso, é possível usar uma operação de consulta com `PK=orderId` e `SK begins_with “i#”`.

**Tabela base:**

![\[Design de tabela com entidade de fatura na coleção de itens do pedido para receber uma fatura por orderId.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-6-Step6.png)


**Etapa 7: abordar o padrão de acesso 8 (`getShipmentByOrderId`)**

Importe [AnOnlineShop\$19.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_9.json) para adicionar entidades `shipment` à coleção de itens de *pedido* e abordar o padrão de acesso 8 (`getShipmentByOrderId`). Estamos estendendo o mesmo modelo particionado verticalmente por meio da adição de mais tipos de entidade no design de tabela única. Observe como a coleção de itens de *pedido* contém os diferentes relacionamentos que um entidade `order` tem com as entidades `shipment`, `orderItem` e `invoice`. 

Para receber envios por `orderId`, você pode realizar uma operação de consulta com `PK=orderId` e `SK begins_with “sh#”`.

**Tabela base:**

![\[Design de tabela com entidade de remessa adicionada à coleção de itens do pedido para receber remessas por ID do pedido.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-7-Step7.png)


**Etapa 8: abordar o padrão de acesso 9 (`getOrderByProductIdForDateRange`)**

Criamos uma coleção de itens de *pedido* na etapa anterior. Esse padrão de acesso tem novas dimensões de pesquisa (`ProductID` e `Date`), que exige que você escaneie toda a tabela e filtre os registros relevantes para buscar os itens específicos. Para abordar esse padrão de acesso, precisaremos criar um [índice secundário global (GSI)](GSI.md). Importe [AnOnlineShop\$110.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_10.json) para criar uma coleção de itens usando o GSI que possibilita a recuperação de dados de `orderItem` de várias coleções de itens de *pedido*. Os dados agora têm `GSI1-PK` e `GSI1-SK`, que serão a chave de partição e a chave de classificação de `GSI1`, respectivamente. 

O DynamoDB preenche automaticamente itens que contêm os principais atributos de um GSI da tabela para o GSI. Não há necessidade de fazer manualmente nenhuma inserção adicional no GSI. 

Para abordar o padrão de acesso 9, execute uma consulta em `GSI1` com `GSI1-PK=productId` e `GSI1SK between (date1, date2)`.

**Tabela base:**

![\[Design de tabela com um GSI para receber dados de pedidos de várias coleções de itens de pedidos.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-8-Step8-Base.png)


**GSI1:**

![\[Design de GSI com ProductID e Date como partição e chaves de classificação para receber pedidos por ID do produto e data.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-9-Step8-GSI.png)


**Etapa 9: abordar os padrões de acesso 10 (`getInvoiceByInvoiceId`) e 11 (`getPaymentByInvoiceId`)**

Importe [AnOnlineShop\$111.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_11.json) para abordar os padrões de acesso 10 (`getInvoiceByInvoiceId`) e 11 (`getPaymentByInvoiceId`), ambos relacionados a `invoice`. Embora esses sejam dois padrões de acesso diferentes, eles são realizados usando a mesma condição de chave. `Payments` são definidos como um atributo com o tipo de dados do mapa na entidade `invoice`.

**nota**  
`GSI1-PK` e `GSI1-SK` estão sobrecarregados para armazenar informações sobre entidades diferentes para que vários padrões de acesso possam ser atendidos por meio do mesmo GSI. Para obter mais informações quanto à sobrecarga do GSI, consulte [Sobrecarga de índices secundários globais no DynamoDB](bp-gsi-overloading.md).

Para abordar os padrões de acesso 10 e 11, consulte `GSI1` com `GSI1-PK=invoiceId` e `GSI1-SK=invoiceId`.

**GSI1:**

![\[Design de GSI com invoiceId como partição e chave de classificação para receber a fatura e o pagamento por ID da fatura.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-10-Step9.png)


**Etapa 10: abordar os padrões de acesso 12 (`getShipmentDetailsByShipmentId`) e 13 (`getShipmentByWarehouseId`)**

Importe [AnOnlineShop\$112.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_12.json) para abordar os padrões de acesso 12 (`getShipmentDetailsByShipmentId`) e 13 (`getShipmentByWarehouseId`). 

Observe que as entidades `shipmentItem` são adicionadas à coleção de itens de *pedido* na tabela base para poder recuperar todos os detalhes sobre um pedido em uma única operação de consulta.

**Tabela base:**

![\[Design de tabela com a entidade shipmentItem na coleção de itens do pedido para receber todos os detalhes do pedido.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-11-Step10.png)


As chaves de partição e de classificação do `GSI1` já foram usadas para modelar uma relação de um para muitos entre `shipment` e `shipmentItem`. Para abordar o padrão de acesso 12 (`getShipmentDetailsByShipmentId`), consulte `GSI1` com `GSI1-PK=shipmentId` e `GSI1-SK=shipmentId`.

**GSI1:**

![\[Design de GSI1 com shipmentId como partição e chave de classificação para receber detalhes da remessa por ID da remessa.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-12-Step10-GSI.png)


Precisaremos criar outro GSI (`GSI2`) para modelar a nova relação de um para muitos entre `warehouse` e `shipment` para o padrão de acesso 13 (`getShipmentByWarehouseId`). Para abordar esse padrão de acesso, consulte `GSI2` com `GSI2-PK=warehouseId` e `GSI2-SK begins_with “sh#”`.

**GSI2:**

![\[Design de GSI2 com warehouseId e shipmentId como partição e chaves de classificação para receber remessas por armazém.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-13-Step10-GSI2.png)


**Etapa 11: abordar os padrões de acesso 14 (`getProductInventoryByWarehouseId`), 15 (`getInvoiceByCustomerIdForDateRange`) e 16 (`getProductsByCustomerIdForDateRange`)**

Importe [AnOnlineShop\$113.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_13.json) para adicionar dados relacionados ao próximo conjunto de padrões de acesso. Para abordar o padrão de acesso 14 (`getProductInventoryByWarehouseId`), consulte `GSI2` com `GSI2-PK=warehouseId` e `GSI2-SK begins_with “p#”`.

**GSI2:**

![\[Design de GSI2 com warehouseId e productId como partição e chaves de classificação para abordar o padrão de acesso 14.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-14-Step11-GSI2.png)


Para abordar o padrão de acesso 15 (`getInvoiceByCustomerIdForDateRange`), consulte `GSI2` com `GSI2-PK=customerId` e `GSI2-SK between (i#date1, i#date2)`.

**GSI2:**

![\[Design de GSI2 com customerId e intervalo de datas da fatura como partição e chaves de classificação para abordar o padrão de acesso 15.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-15-Step11-GSI2.png)


Para abordar o padrão de acesso 16 (`getProductsByCustomerIdForDateRange`), consulte `GSI2` com `GSI2-PK=customerId` e `GSI2-SK between (p#date1, p#date2)`.

**GSI2:**

![\[Design de GSI2 com customerId e intervalo de datas do produto como partição e chaves de classificação para abordar o padrão de acesso 16.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-16-Step11-GSI2.png)


**nota**  
No [NoSQL Workbench](workbench.md), as *facetas* representam os diferentes padrões de acesso a dados de uma aplicação para o DynamoDB. As facetas oferecem uma maneira de visualizar um subconjunto dos dados em uma tabela, sem precisar ver os registros que não atendam às restrições da faceta. As facetas são consideradas uma ferramenta visual de modelagem de dados e não existem como uma estrutura utilizável no DynamoDB, pois são puramente um apoio para a modelagem de padrões de acesso.   
Importe [AnOnlineShop\$1facets.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_facets.json) para ver as facetas desse caso de uso.

Todos os padrões de acesso e a forma como o design do esquema os aborda estão resumidos na tabela abaixo:


| Padrão de acesso | Tabela base/GSI/LSI | Operation | Valor da chave de partição | Valores de chave de classificação | 
| --- | --- | --- | --- | --- | 
| getCustomerByCustomerId | Tabela base | GetItem |  PK=customerId | SK=customerId | 
| getProductByProductId | Tabela base | GetItem |  PK=productId | SK=productId | 
| getWarehouseByWarehouseId | Tabela base | GetItem |  PK=warehouseId | SK=warehouseId | 
| getProductInventoryByProductId | Tabela base | Consulta |  PK=productId | SK begins\$1with "w\$1" | 
| getOrderDetailsByOrderId | Tabela base | Consulta |  PK=orderId |  | 
| getProductByOrderId | Tabela base | Consulta |  PK=orderId | SK begins\$1with "p\$1" | 
| getInvoiceByOrderId |  Tabela base | Consulta |  PK=orderId | SK begins\$1with "i\$1" | 
| getShipmentByOrderId |  Tabela base | Consulta |  PK=orderId | SK begins\$1with "sh\$1" | 
| getOrderByProductIdForDateRange |  GSI1 | Consulta |  PK=productId | SK entre date1 e date2 | 
| getInvoiceByInvoiceId |  GSI1 | Consulta |  PK=invoiceId | SK=invoiceId | 
| getPaymentByInvoiceId |  GSI1 | Consulta |  PK=invoiceId | SK=invoiceId | 
| getShipmentDetailsByShipmentId |  GSI1 | Consulta |  PK=shipmentId | SK=shipmentId | 
| getShipmentByWarehouseId |  GSI2 | Consulta |  PK=warehouseId | SK begins\$1with "sh\$1" | 
| getProductInventoryByWarehouseId |  GSI2 | Consulta |  PK=warehouseId | SK begins\$1with "p\$1" | 
| getInvoiceByCustomerIdForDateRange |  GSI2 | Consulta |  PK=customerId | SK entre i\$1date1 and i\$1date2 | 
| getProductsByCustomerIdForDateRange |  GSI2 | Consulta |  PK=customerId | SK entre p\$1date1 and p\$1date2 | 

### Esquema final da loja on-line
<a name="data-modeling-schema-online-store-final-schema"></a>

Veja aqui os designs do esquema final. Para baixar esse design de esquema como arquivo JSON, consulte [Padrões de design do DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/schema_design/SchemaExamples) no GitHub.

**Tabela base**

![\[Esquema final da tabela base para uma loja on-line com atributos, como EntityName e Name.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-17-Final-BaseTable.png)


**GSI1**

![\[Esquema de GSI1 final para a tabela base de uma loja on-line com atributos, como EntityType.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-18-Final-GSI1.png)


**GSI2**

![\[Esquema de GSI2 final para a tabela base de uma loja on-line com atributos, como EntityType.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-19-Final-GSI2.png)


## Como usar o NoSQL Workbench com esse design de esquema
<a name="data-modeling-schema-online-shop-nosql"></a>

Você pode importar esse esquema final para o [NoSQL Workbench](workbench.md), uma ferramenta visual que fornece atributos de modelagem de dados, visualização de dados e desenvolvimento de consultas para o DynamoDB, se quiser explorar e editar ainda mais seu novo projeto. Para começar, siga estas etapas:

1. Baixe o NoSQL Workbench. Para obter mais informações, consulte [Baixar o NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Baixe o arquivo do esquema JSON listado acima, que já está no formato do modelo NoSQL Workbench.

1. Importe o arquivo do esquema JSON para o NoSQL Workbench. Para obter mais informações, consulte [Importar um modelo de dados existente](workbench.Modeler.ImportExisting.md). 

1. Depois de importar para o NOSQL Workbench, você pode editar o modelo de dados. Para obter mais informações, consulte [Editar um modelo de dados existente](workbench.Modeler.Edit.md).

# Práticas recomendadas para modelagem de dados relacionais no DynamoDB
<a name="bp-relational-modeling"></a>

Esta seção fornece práticas recomendadas para modelagem de dados relacionais no Amazon DynamoDB. Primeiro, apresentamos os conceitos tradicionais de modelagem de dados. Em seguida, descrevemos as vantagens de usar o DynamoDB em relação aos sistemas tradicionais de gerenciamento de banco de dados relacional, mostrando como ele elimina a necessidade de operações de JOIN e reduz as despesas operacionais indiretas. 

Depois, explicamos como criar uma tabela do DynamoDB que escale com eficiência. Por fim, fornecemos um exemplo de como modelar dados relacionais no DynamoDB.

**Topics**
+ [Modelos tradicionais de banco de dados relacional](#SQLtoNoSQL.relational-modeling2)
+ [Como o DynamoDB elimina a necessidade de operações JOIN](#bp-relational-modeling-joins)
+ [Como as transações do DynamoDB eliminam a sobrecarga no processo de gravação](#bp-relational-modeling-transactions)
+ [Primeiras passos para a modelagem de dados relacionais no DynamoDB](bp-modeling-nosql.md)
+ [Exemplo de modelagem de dados relacionais no DynamoDB](bp-modeling-nosql-B.md)

## Modelos tradicionais de banco de dados relacional
<a name="SQLtoNoSQL.relational-modeling2"></a>

Os sistemas de gerenciamento de banco de dados relacional (RDBMS) tradicionais armazenam dados em uma estrutura relacional normalizada. O objetivo do modelo de dados relacional é reduzir a duplicação de dados (por meio da normalização) para apoiar a integridade referencial e reduzir as anomalias de dados. 

O esquema a seguir é um exemplo de um modelo de dados relacional para uma aplicação genérica de entrada de pedidos. A aplicação atende a um esquema de recursos humanos que apoia os sistemas de suporte operacional e comercial de um fabricante fictício.

![\[Exemplo de esquema de RDBMS.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/RDBMS.png)


Como um serviço de banco de dados não relacional, o DynamoDB oferece muitas vantagens em relação aos sistemas tradicionais de gerenciamento de banco de dados relacional. 

## Como o DynamoDB elimina a necessidade de operações JOIN
<a name="bp-relational-modeling-joins"></a>

Um RDBMS usa uma linguagem de consulta estruturada (SQL) para retornar dados à aplicação. Em decorrência da normalização do modelo de dados, essas consultas normalmente exigem o uso do operador `JOIN` para combinar dados de uma ou mais tabelas.

Por exemplo, para gerar uma lista de itens de ordens de compra classificadas pela quantidade em estoque em todos os depósitos que podem enviar cada item, você pode emitir a seguinte consulta de SQL no esquema anterior:

```
SELECT * FROM Orders
  INNER JOIN Order_Items ON Orders.Order_ID = Order_Items.Order_ID
  INNER JOIN Products ON Products.Product_ID = Order_Items.Product_ID
  INNER JOIN Inventories ON Products.Product_ID = Inventories.Product_ID
  ORDER BY Quantity_on_Hand DESC
```

Consultas SQL desse tipo podem fornecer uma API flexível para acesso aos dados, mas exigem um volume significativo de processamento. Cada junção na consulta aumenta a complexidade do tempo de execução da consulta, pois os dados de cada tabela devem ser armazenados e depois montados para retornar o conjunto de resultados. 

Outros fatores que podem afetar o tempo de execução das consultas são o tamanho das tabelas e se as colunas que estão sendo unidas têm índices. A consulta anterior inicia consultas complexas em várias tabelas e, depois, classifica o conjunto de resultados.

Eliminar a necessidade de `JOINs` é o principal objetivo da modelagem de dados NoSQL. É por isso que criamos o DynamoDB para oferecer suporte à Amazon.com e que o DynamoDB pode oferecer performance consistente em qualquer escala. Dada a complexidade do runtime das consultas SQL e `JOINs`, a performance do RDBMS não é constante em larga escala. Isso causa problemas de performance à medida que as aplicações do cliente se ampliam.

Embora a normalização dos dados reduza a quantidade de dados armazenados em disco, geralmente os recursos mais restritos que afetam a performance são o tempo de CPU e a latência da rede. 

O DynamoDB foi criado para minimizar as duas restrições, eliminando `JOINs` (e incentivando a desnormalização dos dados) e otimizando a arquitetura do banco de dados para responder totalmente a uma consulta de aplicação com uma única solicitação para um item. Essas qualidades permitem que o DynamoDB forneça performance de milissegundos de um dígito em qualquer escala. Isso ocorre porque a complexidade do tempo de execução das operações do DynamoDB é constante, independentemente do tamanho dos dados, para padrões comuns de acesso.

## Como as transações do DynamoDB eliminam a sobrecarga no processo de gravação
<a name="bp-relational-modeling-transactions"></a>

Outro fator que pode desacelerar um RDBMS é o uso de transações para gravação em um esquema normalizado. Conforme mostrado no exemplo, as estruturas de dados relacionais usadas pela maioria das aplicações de processamento de transações on-line (OLTP) devem ser divididas e distribuídas entre várias tabelas lógicas quando são armazenadas em um RDBMS. 

Portanto, um framework de transações compatível com ACID é necessário para evitar problemas de integridade de dados e condições de disputa que poderão ocorrer se uma aplicação tentar ler um objeto que esteja em processo de gravação. Esse framework de transações, quanto acoplado a um esquema relacional, pode adicionar uma sobrecarga significativa ao processo de gravação.

A implementação de transações no DynamoDB impede problemas comuns de escalabilidade encontrados em um RDBMS. O DynamoDB faz isso ao emitir uma transação como uma única chamada de API e limitar o número de itens que podem ser acessados nessa única transação. Transações de longa duração podem causar problemas operacionais ao manter os dados bloqueados por muito tempo ou perpetuamente, pois a transação nunca é encerrada. 

Para evitar esses problemas no DynamoDB, as transações foram implementadas com duas operações de API distintas: `TransactWriteItems` e `TransactGetItems`. Essas operações de API não têm semânticas de início e fim, que são comuns em um RDBMS. Além disso, o DynamoDB tem um limite de acesso de 100 itens em uma transação para igualmente evitar transações de longa duração. Para saber mais sobre transações do DynamoDB, consulte [Trabalhar com transações](transactions.md).

Por esses motivos, quando sua empresa precisar de resposta de baixa latência a consultas de alto tráfego, aproveitar as vantagens de um sistema NoSQL normalmente faz sentido do ponto de vista técnico e econômico. O Amazon DynamoDB ajuda a resolver os problemas que limitam a escalabilidade do sistema relacional simplesmente evitando-os.

Normalmente, a performance de um RDBMS não escala bem pelos seguintes motivos:
+ Ele usa junções caras para remontar as visualizações exigidas dos resultados de consulta.
+ Ele normaliza os dados e armazena-os em várias tabelas que exigem várias consultas para gravar em disco.
+ Isso geralmente implica em custos de desempenho de um sistema de transações compatível com ACID.

O DynamoDB tem uma boa escalabilidade por estes motivos:
+ A flexibilidade do esquema permite o DynamoDB armazene dados hierárquicos e complexos em um único item.
+ O design da chave composta permite o armazenamento de itens relacionados na mesma tabela.
+ As transações são realizadas em uma única operação. O limite ao número de itens que podem ser acessados é 100, para evitar operações de longa duração.

As consultas no armazenamento de dados tornam-se muito mais simples, normalmente da seguinte forma:

```
SELECT * FROM Table_X WHERE Attribute_Y = "somevalue"
```

O DynamoDB executa muito menos trabalho para retornar os dados solicitados em comparação ao RDBMS no exemplo anterior.

# Primeiras passos para a modelagem de dados relacionais no DynamoDB
<a name="bp-modeling-nosql"></a>

**nota**  
O design do NoSQL exige uma visão diferente daquela no design do RDBMS. Para um RDBMS, você pode criar um modelo de dados normalizado sem pensar nos padrões de acesso. Você poderá estendê-lo posteriormente quando surgirem novas perguntas e requisitos de consulta. Por outro lado, no Amazon DynamoDB, você não deve iniciar o design do seu esquema até saber quais perguntas ele precisará responder. Compreender os problemas de negócios e os casos de uso de aplicativo antecipadamente é absolutamente essencial.

Para iniciar o design de uma tabela do DynamoDB que poderá ser escalada com eficiência, é necessário realizar várias etapas primeiro para identificar os padrões de acesso exigidos pelos sistemas de suporte operacional e administrativo (OSS/BSS) que o design precisa comportar:
+ Para novos aplicativos, analise as histórias dos usuários referentes a atividades e objetivos. Documente os vários casos de uso identificados e analise os padrões de acesso que eles exigem.
+ Para aplicativos existentes, analise os logs de consulta para saber como as pessoas estão usando o sistema atualmente e quais são os principais padrões de acesso.

Após concluir esse processo, você deve encerrar com uma lista que pode ser semelhante à seguinte:


**Padrões de acesso para uma aplicação de entrada de pedidos**  

| Número do padrão | Padrão de acesso | 
| --- | --- | 
| 1 | Procurar os detalhes do funcionário por ID do funcionário | 
| 2 | Consultar detalhes do funcionário por nome do funcionário | 
| 3 | Encontrar um ou mais números de telefone de um funcionário | 
| 4 | Encontrar um ou mais números de telefone de um cliente | 
| 5 | Receber pedidos de clientes dentro do intervalo de datas | 
| 6 | Mostrar todos os pedidos em aberto dentro do intervalo de datas | 
| 7 | Ver todos os funcionários contratados recentemente | 
| 8 | Encontrar todos os funcionários no armazém | 
| 9 | Obter todos os itens do pedido do produto | 
| 10 | Obter inventários de produtos em todos os armazéns | 
| 11 | Obter clientes por representante de conta | 
| 12 | Obter pedidos por representante de conta | 
| 13 | Obter funcionários com o cargo | 
| 14 | Obter inventário por produto e armazém | 
| 15 | Obter o inventário total de produtos | 

Em um aplicativo real, sua lista pode ser muito mais longa. Mas essa coleção representa a faixa de complexidade dos padrões de consulta que você pode encontrar em um ambiente de produção.

Uma abordagem moderna de design de esquema do DynamoDB usa princípios de agregação, agrupando dados com base em padrões de acesso em vez de limites rígidos de entidade. Essa abordagem considera vários padrões de design:
+ *Design de tabela única*: uso de chaves de classificação compostas, índices secundários globais sobrecarregados e padrões de lista de adjacências para vários tipos de entidade em uma única tabela.
+ *Design de várias tabelas*: uso de tabelas separadas para entidades com características operacionais independentes e baixa correlação de acesso, com GSIs estratégicos para consultas entre entidades.
+ *Design agregado*: incorporação de dados relacionados quando sempre acessados em conjunto (Order \$1 OrderItems) ou uso de coleção de itens para identificar relações (Product \$1 Inventory).

A escolha entre essas abordagens depende de seus padrões de acesso específicos, das características dos dados e dos requisitos operacionais. Você pode usar esses elementos para estruturar os dados, para que um aplicativo possa recuperar o que for necessário para um determinado padrão de acesso, usando uma única consulta em uma tabela ou um índice.

**nota**  
A escolha entre design de tabela única e de várias tabelas depende de seus requisitos específicos. O design de tabela única funciona bem quando as entidades têm alta correlação de acesso e características operacionais semelhantes. O design de várias tabelas é preferível quando as entidades têm requisitos operacionais independentes e padrões de acesso diferentes ou quando você precisa de limites operacionais claros. O exemplo deste guia demonstra uma abordagem de várias tabelas com agregação e desnormalização estratégicas.

Para usar o NoSQL Workbench para DynamoDB a fim de ajudar a visualizar o design da chave de partição, consulte [Criar modelos de dados com o NoSQL Workbench](workbench.Modeler.md).

# Exemplo de modelagem de dados relacionais no DynamoDB
<a name="bp-modeling-nosql-B"></a>

Esse exemplo descreve como modelar dados relacionais no Amazon DynamoDB. O design de tabela do DynamoDB corresponde ao esquema relacional de entrada de pedidos que é mostrado em [Modelagem relacional](bp-relational-modeling.md). Esse design usa várias tabelas especializadas em vez de uma única lista de adjacências, oferecendo limites operacionais claros e utilizando GSIs estratégicos para atender a todos os padrões de acesso com eficiência.

Uma abordagem usa princípios de agregação, agrupando dados com base em padrões de acesso em vez de limites rígidos de entidade. As principais decisões de design incluem o uso de tabelas separadas para entidades com baixa correlação de acesso, a incorporação de dados relacionados quando sempre acessados em conjunto e o uso de coleções de itens para identificar relações.

As seguintes tabelas e os índices que as acompanham permitem usar o esquema de entrada de pedidos relacionais:

## Design de tabela de funcionários
<a name="employee-table-design"></a>

A tabela de funcionários armazena informações sobre os funcionários como uma única entidade por item, é otimizada para consultas diretas sobre funcionários e permite vários padrões de consulta por meio de GSIs estratégicos. Ela demonstra o princípio de criar tabelas separadas para entidades com características operacionais independentes e baixa correlação de acesso entre entidades.

A tabela usa uma chave de partição simples (employee\$1id) sem uma chave de classificação, pois cada funcionário é uma entidade distinta. Quatro GSIs permitem consultas eficientes por atributos diferentes:
+ *GSI EmployeeByName*: usa a projeção INCLUDE com todos os atributos dos funcionários para permitir a recuperação completa de detalhes do funcionário por nome e trata possíveis nomes duplicados com employee\$1id como chave de classificação.
+ *GSI EmployeeByWarehouse*: usa a projeção INCLUDE apenas com atributos essenciais (name, job\$1title, hire\$1date) para minimizar os custos de armazenamento e, ao mesmo tempo, permitir consultas baseadas em armazém.
+ *GSI EmployeeByJobTitle*: permite consultas baseadas em funções com projeção INCLUDE para geração de relatórios e análises organizacionais.
+ *GSI EmployeeByHireDate*: usa um valor de chave de partição estática “EMPLOYEE” com hire\$1date como chave de classificação para permitir consultas eficientes de intervalo de datas referentes a contratações recentes. Como as adições/atualizações de funcionários geralmente são inferiores a 1.000 WCUs, uma única partição pode lidar com a carga de gravação sem problemas de partição com acesso frequente.


**Tabela de funcionários: estrutura da tabela base**  

| employee\$1id (PK) | name | phone\$1numbers | warehouse\$1id | job\$1title | hire\$1date | entity\$1type | 
| --- | --- | --- | --- | --- | --- | --- | 
| emp\$1001 | John | ["\$11-555-0101"] | wh\$1sea | Gerente | 2024-03-15 | EMPLOYEES | 
| emp\$1002 | Jane Doe | ["\$11-555-0102", "\$11-555-0103"] | wh\$1sea | Associate | 2025-01-10 | EMPLOYEES | 
| emp\$1003 | Bob Wilson | ["\$11-555-0104"] | wh\$1pdx | Associate | 2025-06-20 | EMPLOYEES | 
| emp\$1004 | Alice Brown | ["\$11-555-0105"] | wh\$1pdx | Supervisor | 2023-11-05 | EMPLOYEES | 
| emp\$1005 | Mike Davis | ["\$11-555-0106"] | wh\$1sea | Associate | 2025-12-01 | EMPLOYEES | 


**GSI EmployeeByName: suporte a consultas sobre nomes de funcionário**  

| name (GSI-PK) | employee\$1id (GSI-SK) | phone\$1numbers | warehouse\$1id | job\$1title | hire\$1date | 
| --- | --- | --- | --- | --- | --- | 
| Alice Brown | emp\$1004 | ["\$11-555-0105"] | wh\$1pdx | Supervisor | 2023-11-05 | 
| Bob Wilson | emp\$1003 | ["\$11-555-0104"] | wh\$1pdx | Associate | 2025-06-20 | 
| Mike Davis | emp\$1005 | ["\$11-555-0106"] | wh\$1sea | Associate | 2025-12-01 | 
| Jane Doe | emp\$1002 | ["\$11-555-0102", "\$11-555-0103"] | wh\$1sea | Associate | 2025-01-10 | 
| John | emp\$1001 | ["\$11-555-0101"] | wh\$1sea | Gerente | 2024-03-15 | 


**GSI EmployeeByWarehouse: suporte a consultas sobre armazém**  

| warehouse\$1id (GSI-PK) | employee\$1id (GSI-SK) | name | job\$1title | hire\$1date | 
| --- | --- | --- | --- | --- | 
| wh\$1pdx | emp\$1003 | Bob Wilson | Associate | 2025-06-20 | 
| wh\$1pdx | emp\$1004 | Alice Brown | Supervisor | 2023-11-05 | 
| wh\$1sea | emp\$1001 | John | Gerente | 2024-03-15 | 
| wh\$1sea | emp\$1002 | Jane Doe | Associate | 2025-01-10 | 
| wh\$1sea | emp\$1005 | Mike Davis | Associate | 2025-12-01 | 


**GSI EmployeeByJobTitle: suporte a consultas sobre cargos**  

| job\$1title (GSI-PK) | employee\$1id (GSI-SK) | name | warehouse\$1id | hire\$1date | 
| --- | --- | --- | --- | --- | 
| Associate | emp\$1002 | Jane Doe | wh\$1sea | 2025-01-10 | 
| Associate | emp\$1003 | Bob Wilson | wh\$1pdx | 2025-06-20 | 
| Associate | emp\$1005 | Mike Davis | wh\$1sea | 2025-12-01 | 
| Gerente | emp\$1001 | John | wh\$1sea | 2024-03-15 | 
| Supervisor | emp\$1004 | Alice Brown | wh\$1pdx | 2023-11-05 | 


**GSI EmployeeByHireDate: suporte a consultas sobre contratações recentes**  

| entity\$1type (GSI-PK) | hire\$1date (GSI-SK) | employee\$1id | name | warehouse\$1id | 
| --- | --- | --- | --- | --- | 
| EMPLOYEES | 2023-11-05 | emp\$1004 | Alice Brown | wh\$1pdx | 
| EMPLOYEES | 2024-03-15 | emp\$1001 | John | wh\$1sea | 
| EMPLOYEES | 2025-01-10 | emp\$1002 | Jane Doe | wh\$1sea | 
| EMPLOYEES | 2025-06-20 | emp\$1003 | Bob Wilson | wh\$1pdx | 
| EMPLOYEES | 2025-12-01 | emp\$1005 | Mike Davis | wh\$1sea | 

## Design de tabelas de clientes
<a name="customer-table-design"></a>

A tabela de clientes mantém informações sobre o cliente com a desnormalização estratégica de account\$1rep\$1id para permitir consultas eficientes sobre representantes de conta. Essa opção de design opta por uma pequena sobrecarga de armazenamento em prol do desempenho das consultas, eliminando a necessidade de junções entre os dados do cliente e do representante da conta.

A tabela comporta vários números de telefone por cliente usando um atributo de lista, o que demonstra a flexibilidade do esquema do DynamoDB. O GSI único permite fluxos de trabalho de representantes de contas:
+ *GSI CustomerByAccountRep*: usa a projeção INCLUDE com atributos de nome e e-mail para facilitar o gerenciamento de clientes de representantes de contas sem exigir a recuperação completa dos registros dos clientes.


**Tabela de clientes: estrutura da tabela base**  

| customer\$1id (PK) | name | phone\$1numbers | email | account\$1rep\$1id | 
| --- | --- | --- | --- | --- | 
| cust\$1001 | Acme Corp | ["\$11-555-1001"] | contact@acme.com | rep\$1001 | 
| cust\$1002 | TechStart Inc | ["\$11-555-1002", "\$11-555-1003"] | info@techstart.com | rep\$1001 | 
| cust\$1003 | Global Traders | ["\$11-555-1004"] | sales@globaltraders.com | rep\$1002 | 
| cust\$1004 | BuildRight LLC | ["\$11-555-1005"] | orders@buildright.com | rep\$1002 | 
| cust\$1005 | FastShip Co | ["\$11-555-1006"] | support@fastship.com | rep\$1003 | 


**GSI CustomerByAccountRep: suporte a consultas de representantes de contas**  

| account\$1rep\$1id (GSI-PK) | customer\$1id (GSI-SK) | name | email | 
| --- | --- | --- | --- | 
| rep\$1001 | cust\$1001 | Acme Corp | contact@acme.com | 
| rep\$1001 | cust\$1002 | TechStart Inc | info@techstart.com | 
| rep\$1002 | cust\$1003 | Global Traders | sales@globaltraders.com | 
| rep\$1002 | cust\$1004 | BuildRight LLC | orders@buildright.com | 
| rep\$1003 | cust\$1005 | FastShip Co | support@fastship.com | 

## Design de tabela de pedidos
<a name="order-table-design"></a>

A tabela de pedidos usa particionamento vertical com itens separados para cabeçalhos de pedidos e itens de pedidos. Esse design permite consultas eficientes baseadas em produtos, mantendo todos os componentes do pedido na mesma partição para que o acesso seja eficiente. Cada pedido consiste em vários itens:
+ *Cabeçalho do pedido*: contém metadados do pedido com PK=order\$1id, SK=order\$1id.
+ *Itens do pedido*: itens de linha individuais com PK=order\$1id, SK=product\$1id, permitindo consultas diretas sobre produtos.

**nota**  
Essa abordagem de particionamento vertical opta pela simplicidade dos itens de pedido incorporados em prol de uma maior flexibilidade de consulta. Cada item do pedido se torna um item separado do DynamoDB, permitindo consultas eficientes baseadas em produtos e mantendo todos os dados do pedido na mesma partição para aumentar a eficiência da recuperação em uma única solicitação.

A tabela inclui a desnormalização estratégica de account\$1rep\$1id (duplicada da tabela de clientes) para permitir consultas diretas aos representantes de contas sem exigir consultas sobre clientes. Em cenários de gravação de alto throughput, os pedidos OPEN incluem atributos de status e fragmento para permitir a fragmentação de gravação em várias partições.

Quatro GSIs permitem diferentes padrões de consulta com projeções otimizadas:
+ *GSI OrderByCustomerDate*: usa a projeção INCLUDE com resumo do pedido e detalhes do item para permitir a filtragem por intervalo de datas no histórico de pedidos do cliente.
+ *GSI OpenOrdersByDate (esparso, fragmentado)*: usa chave de partição de vários atributos (status \$1 fragmento) com 5 fragmentos para distribuir 5.000 WPS (gravações por segundo) entre partições (1.000 WPS cada, o que corresponde ao limite de 1.000 WCUs por partição do DynamoDB). Indexa somente pedidos OPEN (20% do total), o que pode ajudar a reduzir os custos de armazenamento do GSI. Requer consultas paralelas em todos os cinco fragmentos com mesclagem de resultados do lado do cliente.
+ *GSI OrderByAccountRep*: usa a projeção INCLUDE com atributos de resumo do pedido para permitir fluxos de trabalho de representantes de contas sem detalhes completos do pedido.
+ *GSI ProductInOrders*: criado com base nos registros de OrderItem (PK=order\$1id, SK=product\$1id), este GSI permite que as consultas encontrem todos os pedidos que contêm um produto específico. Usa a projeção INCLUDE com o contexto do pedido (customer\$1id, order\$1date, quantity) para análise da demanda do produto.


**Tabela de pedidos: estrutura da tabela base (particionamento vertical)**  

| PK | SK | customer\$1id | order\$1date | status | account\$1rep\$1id | quantidade | preço | shard (fragmento) | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| ord\$1001 | ord\$1001 | cust\$1001 | 2025-11-15 | FECHADO | rep\$1001 |  |  |  | 
| ord\$1001 | prod\$1100 |  |  |  |  | 5 | 25.00 |  | 
| ord\$1002 | ord\$1002 | cust\$1001 | 2025-12-20 | OPEN | rep\$1001 |  |  | 0 | 
| ord\$1002 | prod\$1101 |  |  |  |  | 10 | 15.00 |  | 
| ord\$1003 | ord\$1003 | cust\$1002 | 2026-01-05 | OPEN | rep\$1001 |  |  | 2 | 
| ord\$1003 | prod\$1100 |  |  |  |  | 3 | 25.00 |  | 


**GSI OrderByCustomerDate: suporte a consultas sobre pedidos de clientes**  

| customer\$1id (GSI-PK) | order\$1date (GSI-SK) | order\$1id | status | total\$1amount | order\$1items | shard (fragmento) | 
| --- | --- | --- | --- | --- | --- | --- | 
| cust\$1001 | 2025-11-15 | ord\$1001 | FECHADO | 225.00 | [\$1product\$1id: "prod\$1100", qty: 5\$1] |  | 
| cust\$1001 | 2025-12-20 | ord\$1002 | OPEN | 150.00 | [\$1product\$1id: "prod\$1101", qty: 10\$1] | 0 | 
| cust\$1002 | 2026-01-05 | ord\$1003 | OPEN | 175.00 | [\$1product\$1id: "prod\$1100", qty: 3\$1] | 2 | 
| cust\$1003 | 2025-10-10 | ord\$1004 | FECHADO | 250.00 | [\$1product\$1id: "prod\$1101", qty: 5\$1] |  | 
| cust\$1004 | 2026-01-03 | ord\$1005 | OPEN | 200.00 | [\$1product\$1id: "prod\$1100", qty: 20\$1] | 1 | 


**GSI OpenOrdersByDate (esparso, fragmentado): suporte a consultas sobre pedidos abertos de alto throughput**  

| status (GSI-PK-1) | shard (GSI-PK-2) | order\$1date (SK) | order\$1id | customer\$1id | account\$1rep\$1id | order\$1items | total\$1amount | 
| --- | --- | --- | --- | --- | --- | --- | --- | 
| OPEN | 0 | 2025-12-20 | ord\$1002 | cust\$1001 | rep\$1001 | [\$1product\$1id: "prod\$1101", qty: 10\$1] | 150.00 | 
| OPEN | 1 | 2026-01-03 | ord\$1005 | cust\$1004 | rep\$1002 | [\$1product\$1id: "prod\$1100", qty: 20\$1] | 200.00 | 
| OPEN | 2 | 2026-01-05 | ord\$1003 | cust\$1002 | rep\$1001 | [\$1product\$1id: "prod\$1100", qty: 3\$1] | 175.00 | 


**GSI OrderByAccountRep: suporte a consultas sobre pedidos de representantes de contas**  

| account\$1rep\$1id (GSI-PK) | order\$1date (GSI-SK) | order\$1id | customer\$1id | status | total\$1amount | 
| --- | --- | --- | --- | --- | --- | 
| rep\$1001 | 2025-11-15 | ord\$1001 | cust\$1001 | FECHADO | 225.00 | 
| rep\$1001 | 2025-12-20 | ord\$1002 | cust\$1001 | OPEN | 150.00 | 
| rep\$1001 | 2026-01-05 | ord\$1003 | cust\$1002 | OPEN | 175.00 | 
| rep\$1002 | 2025-10-10 | ord\$1004 | cust\$1003 | FECHADO | 250.00 | 
| rep\$1002 | 2026-01-03 | ord\$1005 | cust\$1004 | OPEN | 200.00 | 


**GSI ProductInOrders: suporte a consultas sobre pedidos de produtos**  

| product\$1id (GSI-PK) | order\$1id (GSI-SK) | customer\$1id | order\$1date | quantidade | 
| --- | --- | --- | --- | --- | 
| prod\$1100 | ord\$1001 | cust\$1001 | 2025-11-15 | 5 | 
| prod\$1100 | ord\$1003 | cust\$1002 | 2026-01-05 | 3 | 
| prod\$1101 | ord\$1002 | cust\$1001 | 2025-12-20 | 10 | 

## Design de tabela de produtos
<a name="product-table-design"></a>

A tabela de produtos usa o padrão de coleção de itens para armazenar metadados do produto e dados de inventário na mesma partição. Esse design utiliza a relação de identificação entre produtos e inventário: não pode haver inventário sem um produto principal. Usar PK=product\$1id com SK=product\$1id para metadados do produto e SK=warehouse\$1id para itens de inventário elimina a necessidade de uma tabela de inventário e GSI separados e reduz os custos em aproximadamente 50%.

Esse padrão permite consultas eficientes tanto para o inventário individual do armazém (GetItem com chave composta) quanto para todo o inventário do armazém de um produto (consulta na chave de partição). O atributo total\$1inventory no item de metadados do produto oferece agregação desnormalizada para pesquisas rápidas de inventário total.


**Tabela de produtos: estrutura da tabela base (padrão de coleção de itens)**  

| product\$1id (PK) | warehouse\$1id (SK) | product\$1name | categoria | unit\$1price | inventory\$1quantity | total\$1inventory | 
| --- | --- | --- | --- | --- | --- | --- | 
| prod\$1100 | prod\$1100 | Widget A | Hardware da  | 25.00 |  | 500 | 
| prod\$1100 | wh\$1sea |  |  |  | 200 |  | 
| prod\$1100 | wh\$1pdx |  |  |  | 150 |  | 
| prod\$1100 | wh\$1atl |  |  |  | 150 |  | 
| prod\$1101 | prod\$1101 | Gadget B | Electronics | 50.00 |  | 300 | 
| prod\$1101 | wh\$1sea |  |  |  | 100 |  | 
| prod\$1101 | wh\$1pdx |  |  |  | 200 |  | 

Cada tabela é projetada com índices secundários globais (GSIs) específicos para atender de forma eficiente aos padrões de acesso necessários. O design usa princípios de agregação com desnormalização estratégica e indexação esparsa para otimizar o desempenho e o custo.

As principais otimizações de design incluem:
+ *GSI esparso*: OpenOrdersByDate indexa somente pedidos OPEN (20% do total), o que pode ajudar a reduzir os custos de armazenamento do GSI.
+ *Padrão de coleção de itens*: a tabela de produtos armazena o inventário usando PK=product\$1id, SK=warehouse\$1id para eliminar uma tabela de inventário separada.
+ *Agregação de Order \$1 OrderItems*: incorporada como item único devido à correlação de acesso de 100%.
+ *Desnormalização estratégica*: account\$1rep\$1id é duplicado na tabela de pedidos melhorar a eficiência das consultas.

Por fim, você pode reanalisar os padrões de acesso que foram definidos anteriormente. A tabela a seguir mostra como cada padrão de acesso é atendido de forma eficiente usando o design de várias tabelas com GSIs estratégicos. Cada padrão usa pesquisas de chave diretas ou consultas de GSI único, o que evita verificações caras e oferece desempenho consistente em qualquer escala.


| S. Não. | Padrões de acesso | Condições de consulta | 
| --- | --- | --- | 
|  1  |  Procurar os detalhes do funcionário por ID do funcionário  |  Tabela de funcionários: GetItem(employee\$1id="emp\$1001")  | 
|  2  |  Consultar detalhes do funcionário por nome do funcionário  |  GSI EmployeeByName: Query(name="John Smith")  | 
|  3  |  Encontrar um ou mais números de telefone de um funcionário  |  Tabela de funcionários: GetItem(employee\$1id="emp\$1001")  | 
|  4  |  Encontrar um ou mais números de telefone de um cliente  |  Tabela de clientes: GetItem(customer\$1id="cust\$1001")  | 
|  5  |  Receber pedidos de clientes dentro do intervalo de datas  |  GSI OrderByCustomerDate: Query(customer\$1id="cust\$1001", order\$1date BETWEEN "2025-01-01" AND "2025-12-31")  | 
|  6  |  Mostrar todos os pedidos em aberto dentro do intervalo de datas  |  GSI OpenOrdersByDate: Query 5 shards in parallel with multi-attribute PK (status="OPEN" \$1 shard=0-4), SK=order\$1date BETWEEN "2025-01-01" AND "2025-12-31", merge results  | 
|  7  |  Ver todos os funcionários contratados recentemente  |  GSI EmployeeByHireDate: Query(entity\$1type="EMPLOYEE", hire\$1date >= "2025-01-01")  | 
|  8  |  Encontrar todos os funcionários no armazém  |  GSI EmployeeByWarehouse: Query(warehouse\$1id="wh\$1sea")  | 
|  9  |  Obter todos os itens do pedido do produto  |  GSI ProductInOrders: Query(product\$1id="prod\$1100")  | 
|  10  |  Obter inventários de produtos em todos os armazéns  |  Tabela de produtos: Query(product\$1id="prod\$1100")  | 
|  11  |  Obter clientes por representante de conta  |  GSI CustomerByAccountRep: Query(account\$1rep\$1id="rep\$1001")  | 
|  12  |  Obter pedidos por representante de conta  |  GSI OrderByAccountRep: Query(account\$1rep\$1id="rep\$1001")  | 
|  13  |  Obter funcionários com o cargo  |  GSI EmployeeByJobTitle: Query(job\$1title="Manager")  | 
|  14  |  Obter inventário por produto e armazém  |  Tabela de produtos: GetItem(product\$1id="prod\$1100", warehouse\$1id="wh\$1sea")  | 
|  15  |  Obter o inventário total de produtos  |  Tabela de produtos: GetItem(product\$1id="prod\$1100", warehouse\$1id="prod\$1100")  | 