Exemplo de modelagem de dados relacionais no DynamoDB - Amazon DynamoDB

Exemplo de modelagem de dados relacionais no DynamoDB

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. 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 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_id) 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_id como chave de classificação.

  • GSI EmployeeByWarehouse: usa a projeção INCLUDE apenas com atributos essenciais (name, job_title, hire_date) 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_date 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_id (PK) name phone_numbers warehouse_id job_title hire_date entity_type
emp_001 John ["+1-555-0101"] wh_sea Gerente 2024-03-15 EMPLOYEES
emp_002 Jane Doe ["+1-555-0102", "+1-555-0103"] wh_sea Associate 2025-01-10 EMPLOYEES
emp_003 Bob Wilson ["+1-555-0104"] wh_pdx Associate 2025-06-20 EMPLOYEES
emp_004 Alice Brown ["+1-555-0105"] wh_pdx Supervisor 2023-11-05 EMPLOYEES
emp_005 Mike Davis ["+1-555-0106"] wh_sea Associate 2025-12-01 EMPLOYEES
GSI EmployeeByName: suporte a consultas sobre nomes de funcionário
name (GSI-PK) employee_id (GSI-SK) phone_numbers warehouse_id job_title hire_date
Alice Brown emp_004 ["+1-555-0105"] wh_pdx Supervisor 2023-11-05
Bob Wilson emp_003 ["+1-555-0104"] wh_pdx Associate 2025-06-20
Mike Davis emp_005 ["+1-555-0106"] wh_sea Associate 2025-12-01
Jane Doe emp_002 ["+1-555-0102", "+1-555-0103"] wh_sea Associate 2025-01-10
John emp_001 ["+1-555-0101"] wh_sea Gerente 2024-03-15
GSI EmployeeByWarehouse: suporte a consultas sobre armazém
warehouse_id (GSI-PK) employee_id (GSI-SK) name job_title hire_date
wh_pdx emp_003 Bob Wilson Associate 2025-06-20
wh_pdx emp_004 Alice Brown Supervisor 2023-11-05
wh_sea emp_001 John Gerente 2024-03-15
wh_sea emp_002 Jane Doe Associate 2025-01-10
wh_sea emp_005 Mike Davis Associate 2025-12-01
GSI EmployeeByJobTitle: suporte a consultas sobre cargos
job_title (GSI-PK) employee_id (GSI-SK) name warehouse_id hire_date
Associate emp_002 Jane Doe wh_sea 2025-01-10
Associate emp_003 Bob Wilson wh_pdx 2025-06-20
Associate emp_005 Mike Davis wh_sea 2025-12-01
Gerente emp_001 John wh_sea 2024-03-15
Supervisor emp_004 Alice Brown wh_pdx 2023-11-05
GSI EmployeeByHireDate: suporte a consultas sobre contratações recentes
entity_type (GSI-PK) hire_date (GSI-SK) employee_id name warehouse_id
EMPLOYEES 2023-11-05 emp_004 Alice Brown wh_pdx
EMPLOYEES 2024-03-15 emp_001 John wh_sea
EMPLOYEES 2025-01-10 emp_002 Jane Doe wh_sea
EMPLOYEES 2025-06-20 emp_003 Bob Wilson wh_pdx
EMPLOYEES 2025-12-01 emp_005 Mike Davis wh_sea

Design de tabelas de clientes

A tabela de clientes mantém informações sobre o cliente com a desnormalização estratégica de account_rep_id 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_id (PK) name phone_numbers email account_rep_id
cust_001 Acme Corp ["+1-555-1001"] contact@acme.com rep_001
cust_002 TechStart Inc ["+1-555-1002", "+1-555-1003"] info@techstart.com rep_001
cust_003 Global Traders ["+1-555-1004"] sales@globaltraders.com rep_002
cust_004 BuildRight LLC ["+1-555-1005"] orders@buildright.com rep_002
cust_005 FastShip Co ["+1-555-1006"] support@fastship.com rep_003
GSI CustomerByAccountRep: suporte a consultas de representantes de contas
account_rep_id (GSI-PK) customer_id (GSI-SK) name email
rep_001 cust_001 Acme Corp contact@acme.com
rep_001 cust_002 TechStart Inc info@techstart.com
rep_002 cust_003 Global Traders sales@globaltraders.com
rep_002 cust_004 BuildRight LLC orders@buildright.com
rep_003 cust_005 FastShip Co support@fastship.com

Design de tabela de pedidos

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_id, SK=order_id.

  • Itens do pedido: itens de linha individuais com PK=order_id, SK=product_id, 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_rep_id (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 + 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_id, SK=product_id), 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_id, order_date, quantity) para análise da demanda do produto.

Tabela de pedidos: estrutura da tabela base (particionamento vertical)
PK SK customer_id order_date status account_rep_id quantidade preço shard (fragmento)
ord_001 ord_001 cust_001 2025-11-15 FECHADO rep_001
ord_001 prod_100 5 25.00
ord_002 ord_002 cust_001 2025-12-20 OPEN rep_001 0
ord_002 prod_101 10 15.00
ord_003 ord_003 cust_002 2026-01-05 OPEN rep_001 2
ord_003 prod_100 3 25.00
GSI OrderByCustomerDate: suporte a consultas sobre pedidos de clientes
customer_id (GSI-PK) order_date (GSI-SK) order_id status total_amount order_items shard (fragmento)
cust_001 2025-11-15 ord_001 FECHADO 225.00 [{product_id: "prod_100", qty: 5}]
cust_001 2025-12-20 ord_002 OPEN 150.00 [{product_id: "prod_101", qty: 10}] 0
cust_002 2026-01-05 ord_003 OPEN 175.00 [{product_id: "prod_100", qty: 3}] 2
cust_003 2025-10-10 ord_004 FECHADO 250.00 [{product_id: "prod_101", qty: 5}]
cust_004 2026-01-03 ord_005 OPEN 200.00 [{product_id: "prod_100", qty: 20}] 1
GSI OpenOrdersByDate (esparso, fragmentado): suporte a consultas sobre pedidos abertos de alto throughput
status (GSI-PK-1) shard (GSI-PK-2) order_date (SK) order_id customer_id account_rep_id order_items total_amount
OPEN 0 2025-12-20 ord_002 cust_001 rep_001 [{product_id: "prod_101", qty: 10}] 150.00
OPEN 1 2026-01-03 ord_005 cust_004 rep_002 [{product_id: "prod_100", qty: 20}] 200.00
OPEN 2 2026-01-05 ord_003 cust_002 rep_001 [{product_id: "prod_100", qty: 3}] 175.00
GSI OrderByAccountRep: suporte a consultas sobre pedidos de representantes de contas
account_rep_id (GSI-PK) order_date (GSI-SK) order_id customer_id status total_amount
rep_001 2025-11-15 ord_001 cust_001 FECHADO 225.00
rep_001 2025-12-20 ord_002 cust_001 OPEN 150.00
rep_001 2026-01-05 ord_003 cust_002 OPEN 175.00
rep_002 2025-10-10 ord_004 cust_003 FECHADO 250.00
rep_002 2026-01-03 ord_005 cust_004 OPEN 200.00
GSI ProductInOrders: suporte a consultas sobre pedidos de produtos
product_id (GSI-PK) order_id (GSI-SK) customer_id order_date quantidade
prod_100 ord_001 cust_001 2025-11-15 5
prod_100 ord_003 cust_002 2026-01-05 3
prod_101 ord_002 cust_001 2025-12-20 10

Design de tabela de produtos

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_id com SK=product_id para metadados do produto e SK=warehouse_id 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_inventory 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_id (PK) warehouse_id (SK) product_name categoria unit_price inventory_quantity total_inventory
prod_100 prod_100 Widget A Hardware da 25.00 500
prod_100 wh_sea 200
prod_100 wh_pdx 150
prod_100 wh_atl 150
prod_101 prod_101 Gadget B Electronics 50.00 300
prod_101 wh_sea 100
prod_101 wh_pdx 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_id, SK=warehouse_id para eliminar uma tabela de inventário separada.

  • Agregação de Order + OrderItems: incorporada como item único devido à correlação de acesso de 100%.

  • Desnormalização estratégica: account_rep_id é 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_id="emp_001")

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_id="emp_001")

4

Encontrar um ou mais números de telefone de um cliente

Tabela de clientes: GetItem(customer_id="cust_001")

5

Receber pedidos de clientes dentro do intervalo de datas

GSI OrderByCustomerDate: Query(customer_id="cust_001", order_date 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" + shard=0-4), SK=order_date BETWEEN "2025-01-01" AND "2025-12-31", merge results

7

Ver todos os funcionários contratados recentemente

GSI EmployeeByHireDate: Query(entity_type="EMPLOYEE", hire_date >= "2025-01-01")

8

Encontrar todos os funcionários no armazém

GSI EmployeeByWarehouse: Query(warehouse_id="wh_sea")

9

Obter todos os itens do pedido do produto

GSI ProductInOrders: Query(product_id="prod_100")

10

Obter inventários de produtos em todos os armazéns

Tabela de produtos: Query(product_id="prod_100")

11

Obter clientes por representante de conta

GSI CustomerByAccountRep: Query(account_rep_id="rep_001")

12

Obter pedidos por representante de conta

GSI OrderByAccountRep: Query(account_rep_id="rep_001")

13

Obter funcionários com o cargo

GSI EmployeeByJobTitle: Query(job_title="Manager")

14

Obter inventário por produto e armazém

Tabela de produtos: GetItem(product_id="prod_100", warehouse_id="wh_sea")

15

Obter o inventário total de produtos

Tabela de produtos: GetItem(product_id="prod_100", warehouse_id="prod_100")