Ejemplo de modelado de datos relacionales en DynamoDB - Amazon DynamoDB

Ejemplo de modelado de datos relacionales en DynamoDB

En este ejemplo, se describe cómo se modelan los datos relacionales en Amazon DynamoDB. El diseño de las tablas de DynamoDB se corresponde con el esquema relacional de registro de pedidos que se muestra en Modelos relacionales. Este diseño utiliza varias tablas especializadas en lugar de una sola lista de adyacencias, lo que proporciona límites operativos claros y, al mismo tiempo, aprovecha los GSI estratégicos para atender todos los patrones de acceso de manera eficiente.

El enfoque del diseño utiliza principios orientados a los agregados, que agrupan los datos en función de los patrones de acceso en lugar de los límites rígidos de las entidades. Las principales decisiones de diseño incluyen el uso de tablas independientes para las entidades con una baja correlación de acceso, la incrustación de los datos relacionados cuando siempre se accede a ellos juntos y el uso de recopilaciones de elementos para identificar las relaciones.

Las siguientes tablas y los índices que las acompañan respaldan el esquema de registro de pedidos relacionales:

Diseño de tabla de empleados

La tabla de empleados almacena la información de los empleados como una sola entidad por elemento, optimizada para las búsquedas directas de los empleados y compatible con múltiples patrones de consulta a través de GSI estratégicos. En esta tabla, se muestra el principio de diseñar tablas independientes para entidades con características operativas independientes y una baja correlación de acceso entre entidades.

La tabla utiliza una clave de partición simple (employee_id) sin una clave de clasificación, ya que cada empleado es una entidad distinta. Cuatro GSI permiten realizar consultas eficientes por diferentes atributos:

  • EmployeeByName GSI: utiliza la proyección INCLUDE con todos los atributos de los empleados para facilitar la recuperación completa de los detalles de los empleados por nombre, gestiona los posibles nombres duplicados con employee_id como clave de clasificación.

  • EmployeeByWarehouse GSI: utiliza la proyección INCLUDE solo con los atributos esenciales (name, job_title, hire_date) para minimizar los costes de almacenamiento y, al mismo tiempo, permitir las consultas basadas en el almacén.

  • EmployeeByJobTitle GSI: permite realizar consultas basadas en roles con la proyección INCLUDE para la elaboración de informes y el análisis de la organización.

  • EmployeeByHireDate GSI: utiliza un valor de clave de partición estática “EMPLOYEE” con hire_date como clave de clasificación para permitir consultas eficientes por intervalos de fechas para las contrataciones recientes. Dado que las incorporaciones o actualizaciones de los empleados suelen ser inferiores a 1000 WCU, una sola partición puede gestionar la carga de escritura sin problemas relacionados con las particiones más frecuentes.

Tabla de empleados: estructura de la tabla base
employee_id (PK) name phone_numbers warehouse_id job_title hire_date entity_type
emp_001 John Smith [“+1-555-0101”] wh_sea Manager 2024-03-15 EMPLEADO
emp_002 Jane Doe [“+1-555-0102”, “+1-555-0103”] wh_sea Asociar 2025-01-10 EMPLEADO
emp_003 Bob Wilson [“+1-555-0104”] wh_pdx Asociar 2025-06-20 EMPLEADO
emp_004 Alice Brown [“+1-555-0105”] wh_pdx Supervisor 2023-11-05 EMPLEADO
emp_005 Charlie Davis [“+1-555-0106”] wh_sea Asociar 2025-12-01 EMPLEADO
EmployeeByName GSI: compatibilidad de consultas de nombre de empleado
nombre (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 Asociar 2025-06-20
Charlie Davis emp_005 [“+1-555-0106”] wh_sea Asociar 2025-12-01
Jane Doe emp_002 [“+1-555-0102”, “+1-555-0103”] wh_sea Asociar 2025-01-10
John Smith emp_001 [“+1-555-0101”] wh_sea Manager 2024-03-15
EmployeeByWarehouse GSI: compatibilidad de consultas de almacén
warehouse_id (GSI-PK) employee_id (GSI-SK) name job_title hire_date
wh_pdx emp_003 Bob Wilson Asociar 2025-06-20
wh_pdx emp_004 Alice Brown Supervisor 2023-11-05
wh_sea emp_001 John Smith Manager 2024-03-15
wh_sea emp_002 Jane Doe Asociar 2025-01-10
wh_sea emp_005 Charlie Davis Asociar 2025-12-01
EmployeeByJobTitle GSI: compatibilidad de consultas de títulos de trabajo
job_title (GSI-PK) employee_id (GSI-SK) name warehouse_id hire_date
Asociar emp_002 Jane Doe wh_sea 2025-01-10
Asociar emp_003 Bob Wilson wh_pdx 2025-06-20
Asociar emp_005 Charlie Davis wh_sea 2025-12-01
Manager emp_001 John Smith wh_sea 2024-03-15
Supervisor emp_004 Alice Brown wh_pdx 2023-11-05
EmployeeByHireDate GSI: compatibilidad de consultas de contrataciones recientes
entity_type (GSI-PK) hire_date (GSI-SK) employee_id name warehouse_id
EMPLEADO 2023-11-05 emp_004 Alice Brown wh_pdx
EMPLEADO 2024-03-15 emp_001 John Smith wh_sea
EMPLEADO 2025-01-10 emp_002 Jane Doe wh_sea
EMPLEADO 2025-06-20 emp_003 Bob Wilson wh_pdx
EMPLEADO 2025-12-01 emp_005 Charlie Davis wh_sea

Diseño de tabla de clientes

La tabla de clientes mantiene la información de los clientes con la desnormalización estratégica de account_rep_id para permitir consultas eficientes de los representantes de las cuentas. Esta opción de diseño reduce una pequeña sobrecarga de almacenamiento en beneficio del rendimiento de las consultas, lo que elimina la necesidad de unir los datos de los clientes y los de los representantes de la cuenta.

La tabla admite varios números de teléfono por cliente mediante un atributo de lista, lo que demuestra la flexibilidad del esquema de DynamoDB. El GSI único permite los flujos de trabajo de los representantes de cuentas:

  • CustomerByAccountRep GSI: utiliza la proyección INCLUDE con los atributos de nombre y correo electrónico para facilitar la administración de clientes del representante de cuentas sin necesidad de recuperar todos los registros de los clientes.

Tabla de clientes: estructura de la tabla base
customer_id (PK) name phone_numbers correo electrónico 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
CustomerByAccountRep GSI: compatibilidad de consultas de representantes de cuentas
account_rep_id (GSI-PK) customer_id (GSI-SK) name correo electrónico
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

Diseño de tabla de pedidos

La tabla de pedidos utiliza una partición vertical con elementos independientes para los encabezados de los pedidos y los elementos de los pedidos. Este diseño permite realizar consultas eficientes basadas en el producto y, al mismo tiempo, mantener todos los componentes del pedido dentro de la misma partición para un acceso eficiente. Cada pedido consta de varios elementos:

  • Encabezado del pedido: contiene los metadatos del pedido con PK=order_id, SK=order_id

  • Elementos del pedido: elementos de línea individuales con PK=order_id, SK=product_id, lo que permite realizar consultas directas de productos

nota

Este enfoque de partición vertical compensa la simplicidad de los elementos de pedido incrustados en favor de una mayor flexibilidad de consulta. Cada elementos del pedido se convierte en un elemento independiente de DynamoDB, lo que permite realizar consultas eficientes basadas en el producto y, al mismo tiempo, mantener todos los datos del pedido en la misma partición para poder recuperarlos de forma eficaz en una sola solicitud.

La tabla incluye la desnormalización estratégica de account_rep_id (un duplicado de la tabla de clientes) para permitir consultas directas a los representantes de las cuentas sin necesidad de buscar a los clientes. Para escenarios de escritura de alto rendimiento, los pedidos ABIERTOS incluyen los atributos de estado y partición para permitir la fragmentación de escritura en varias particiones.

Cuatro GSI admiten diferentes patrones de consulta con proyecciones optimizadas:

  • OrderByCustomerDate GSI: utiliza la proyección INCLUDE con el resumen del pedido y los detalles de los elementos para respaldar el historial de pedidos de los clientes con un filtrado por intervalos de fechas

  • OpenOrdersByDate GSI (disperso, particionado): utiliza una clave de partición con varios atributos (estado + partición) con 5 particiones para distribuir 5000 WPS (escrituras por segundo) entre las particiones (1000 WPS cada una, lo que equivale al límite de 1000 WCU por partición de DynamoDB). Solo indexa los pedidos ABIERTOS (el 20 % del total), lo que puede ayudar a reducir los costos de almacenamiento de GSI. Requiere consultas paralelas en las 5 particiones con la fusión de los resultados del cliente

  • OrderByAccountRep GSI: utiliza la proyección INCLUDE con los atributos del resumen del pedido para respaldar los flujos de trabajo representativos de las cuentas sin tener todos los detalles del pedido

  • ProductInOrders GSI: a partir de registros de OrderItem (PK=order_id, SK=product_id), este GSI permite realizar consultas para encontrar todos los pedidos que contengan un producto específico. Usa la proyección INCLUDE con el contexto del pedido (customer_id, order_date, quantity) para el análisis de la demanda de productos

Tabla de pedidos: estructura de la tabla base (partición vertical)
PK SK customer_id order_date status account_rep_id quantity precio partición
ord_001 ord_001 cust_001 2025-11-15 CLOSED 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
OrderByCustomerDate GSI: compatibilidad de consultas de pedidos de clientes
customer_id (GSI-PK) order_date (GSI-SK) order_id status total_amount order_items partición
cust_001 2025-11-15 ord_001 CLOSED 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 CLOSED 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
OpenOrdersByDate GSI (disperso, particionado): compatibilidad de consultas de pedidos abiertos de alto rendimiento
estado (GSI-PK-1) partición (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
OrderByAccountRep GSI: compatibilidad de consultas de pedidos de representantes de cuentas
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 CLOSED 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 CLOSED 250.00
rep_002 2026-01-03 ord_005 cust_004 OPEN 200.00
ProductInOrders GSI: compatibilidad de consultas de pedidos de productos
product_id (GSI-PK) order_id (GSI-SK) customer_id order_date quantity
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

Diseño de tabla de productos

La tabla de productos utiliza el patrón de recopilación de elementos para almacenar los metadatos del producto y los datos de inventario en la misma partición. Este diseño aprovecha la relación de identificación entre los productos y el inventario: el inventario no puede existir sin un producto principal. El uso de PK=product_id con SK=product_id para los metadatos del producto y SK=warehouse_id para los elementos del inventario elimina la necesidad de tener una tabla de inventario y un GSI independientes, lo que reduce los costos en aproximadamente un 50 %.

Este patrón permite realizar consultas eficientes tanto para el inventario de almacén individual (GetItem con clave compuesta) como para todo el inventario de almacén de un producto (consulta en clave de partición). El atributo total_inventory del elemento de metadatos del producto proporciona una agregación desnormalizada para realizar búsquedas rápidas del inventario total.

Tabla de productos: estructura de la tabla base (patrón de recopilación de elementos)
product_id (PK) warehouse_id (SK) product_name categoría unit_price inventory_quantity total_inventory
prod_100 prod_100 Widget A Hardware de 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 tabla está diseñada con índices secundarios globales (GSI) específicos para respaldar los patrones de acceso requeridos de manera eficiente. El diseño utiliza principios orientados a los agregados con una desnormalización estratégica y una indexación dispersa para optimizar tanto el rendimiento como los costos.

Las principales optimizaciones de diseño incluyen:

  • GSI disperso: OpenOrdersByDate solo indexa los pedidos ABIERTOS (20 % del total), que puede ayudar a reducir los costos de almacenamiento de GSI

  • Patrón de recolección de elementos: la tabla de productos almacena el inventario mediante PK=product_id y SK=warehouse_id para eliminar la tabla de inventario independiente

  • Agregación de pedido + OrderItems: incrustado como un solo elemento debido a una correlación de acceso del 100 %

  • Desnormalización estratégica: account_rep_id duplicado en la tabla de pedidos para facilitar las consultas

Por último, puede volver a consultar los patrones de acceso que se definieron anteriormente. En la tabla siguiente, se muestra cómo se admite cada patrón de acceso de manera eficiente mediante el diseño de varias tablas con GSI estratégicos. Cada patrón utiliza búsquedas de claves directas o consultas de GSI únicas, lo que evita análisis costosos y proporciona un rendimiento coherente a cualquier escala.

S. No. Patrones de acceso Condiciones de la consulta

1

Buscar detalles de empleado por ID de empleado

Tabla de empleados: GetItem(employee_id="emp_001")

2

Consultar detalles de empleado por nombre de empleado

EmployeeByName GSI: Query(name="John Smith")

3

Encontrar los números de teléfono de un empleado

Tabla de empleados: GetItem(employee_id="emp_001")

4

Encontrar los números de teléfono de un cliente

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

5

Obtener los pedidos de los clientes dentro del rango de fechas

OrderByCustomerDate GSI: Query(customer_id="cust_001", order_date BETWEEN "2025-01-01" AND "2025-12-31")

6

Mostrar todos los pedidos abiertos dentro del rango de fechas

OpenOrdersByDate GSI: consulte 5 particiones en paralelo con PK de varios atributos (status="OPEN" + shard=0-4), SK=order_date BETWEEN "2025-01-01" AND "2025-12-31", resultados de combinación

7

Ver todos los empleados contratados recientemente

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

8

Encontrar a todos los empleados en un almacén

EmployeeByWarehouse GSI: Query(warehouse_id="wh_sea")

9

Obtener todos los artículos del pedido por producto

ProductInOrders GSI: Query(product_id="prod_100")

10

Obtener inventarios de productos en todos los almacenes

Tabla de productos: Query(product_id="prod_100")

11

Obtener clientes por representante de cuenta

CustomerByAccountRep GSI: Query(account_rep_id="rep_001")

12

Obtener pedidos por representante de cuenta

OrderByAccountRep GSI: Query(account_rep_id="rep_001")

13

Obtener empleados con título de trabajo

EmployeeByJobTitle GSI: Query(job_title="Manager")

14

Obtener inventario por producto y almacén

Tabla de productos: GetItem(product_id="prod_100", warehouse_id="wh_sea")

15

Obtener inventario de productos total

Tabla de productos: GetItem(product_id="prod_100", warehouse_id="prod_100")