Skip to content
SP StackPractices
intermediate

Guía de Diseño de Bases de Datos

Guía práctica para diseñar bases de datos relacionales con normalización, indexación y modelado de relaciones.

Resumen

Una base de datos bien diseñada es la fundación de aplicaciones confiables. Un mal diseño conduce a inconsistencias de datos, consultas lentas y migraciones costosas. Esta guía cubre los principios esenciales para diseñar bases de datos relacionales escalables.

Modelado Entidad-Relación

Comienza cada diseño identificando entidades y relaciones.

Pasos

  1. Identificar entidades: Usuarios, Órdenes, Productos, Categorías
  2. Definir atributos: ¿Qué datos tiene cada entidad?
  3. Mapear relaciones: Uno-a-uno, uno-a-muchos, muchos-a-muchos
  4. Asignar claves: Claves primarias, candidatas, compuestas

Tipos de Relaciones

TipoEjemploImplementación
Uno-a-UnoUsuario → PerfilClave foránea con constraint único
Uno-a-MuchosCategoría → ProductosClave foránea en el lado “muchos”
Muchos-a-MuchosEstudiantes ↔ CursosTabla intermedia con dos claves foráneas

Normalización

La normalización reduce la redundancia y previene anomalías.

Primera Forma Normal (1NF)

  • Valores atómicos: sin atributos multivaluados
  • Cada fila es única (tiene clave primaria)

Segunda Forma Normal (2NF)

  • Debe estar en 1NF
  • Sin dependencia parcial: atributos no clave dependen de la clave primaria completa

Tercera Forma Normal (3NF)

  • Debe estar en 2NF
  • Sin dependencia transitiva: atributos no clave dependen solo de la clave primaria

Ejemplo de Esquema Normalizado

CREATE TABLE users (
  id         SERIAL PRIMARY KEY,
  email      VARCHAR(255) NOT NULL UNIQUE,
  name       VARCHAR(100) NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE orders (
  id          SERIAL PRIMARY KEY,
  user_id     INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  total       DECIMAL(10,2) NOT NULL,
  status      VARCHAR(20) NOT NULL DEFAULT 'pending',
  created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_orders_user ON orders(user_id);
CREATE INDEX idx_orders_status ON orders(status) WHERE status != 'archived';

Estrategias de Indexación

Los índices aceleran lecturas pero ralentizan escrituras.

Cuándo Indexar

EscenarioTipo de Índice
Búsquedas primariasB-Tree en clave primaria
Columnas de clave foráneaB-Tree en columnas FK
Búsqueda full-textÍndice full-text
Consultas por rangoB-Tree en la columna
Datos geoespacialesGiST / SP-GiST

Errores Comunes

  • Indexación excesiva: cada índice ralentiza INSERT/UPDATE/DELETE
  • Indexar columnas de baja cardinalidad solas
  • Ignorar índices de cobertura para consultas frecuentes

Constraints e Integridad de Datos

ConstraintPropósito
PRIMARY KEYIdentificador único para cada fila
UNIQUEAsegura valores sin duplicados
NOT NULLPreviene valores faltantes
CHECKValida datos con expresiones
FOREIGN KEYMantiene integridad referencial

Buenas Prácticas

  • Usar claves sustitutas (auto-increment o UUIDs) en vez de claves naturales
  • Evitar claves foráneas nulas: usa tablas de intersección para relaciones opcionales
  • Elegir tipos de datos cuidadosamente: VARCHAR(255) vs TEXT, DECIMAL vs FLOAT
  • Documentar el schema: con comentarios y diagramas ER
  • Planificar el crecimiento: particionar tablas grandes antes de que se conviertan en un problema

Errores Comunes

  • Saltarse la normalización por “performance” sin evidencia
  • Usar ENUM para valores que cambian frecuentemente
  • Faltar reglas ON DELETE / ON UPDATE en claves foráneas
  • Almacenar datos derivados/calculados en vez de computar en lectura

Preguntas Frecuentes

Qué forma de normalización de base de datos debería usar?

La mayoría de aplicaciones deberían normalizar al menos a Tercera Forma Normal (3NF). Esto elimina dependencias transitivas y mantiene datos consistentes. Desnormaliza solo cuando tengas problemas de performance comprobados.

Cuándo debería usar un índice compuesto?

Usa índices compuestos cuando las queries filtren por múltiples columnas juntas. Ordena las columnas por selectividad (la más selectiva primero). Evita indexar columnas que rara vez se usan en WHERE clauses.

Debería usar UUID o auto-increment para claves primarias?

Usa enteros auto-increment para la mayoría de aplicaciones OLTP — son más pequeños, más rápidos de indexar y legibles. Usa UUIDs cuando necesites generación distribuida o merge replication entre bases de datos.