StackPractices
intermediate Por Mathias Paulenko

Normalización de Bases de Datos — 1NF a 5NF Explicado

Guía visual de normalización de bases de datos: aprende 1NF a 5NF con ejemplos prácticos, cuándo aplicar cada forma y cómo balancear normalización con rendimiento.

Overview

La normalización toma una tabla cruda — donde el mismo dato vive en veinte filas y actualizar un sitio rompe otro — y la divide en tablas más pequeñas que describen una sola cosa cada una. Las formas normales (de 1NF a 5NF) son una escalera de reglas que elimina un tipo concreto de redundancia en cada peldaño. La mayoría de los esquemas en producción paran en 3NF o BCNF; las formas altas importan para entrevistas, casos límite raros y saber exactamente qué sacrificas cuando desnormalizas a propósito.

Cuándo usarla

  • Diseñar esquemas relacionales desde cero
  • Refactorizar bases de datos legacy con datos duplicados
  • Preparar esquemas para cargas transaccionales (OLTP)
  • Antes de decidir qué desnormalizar para reportes (OLAP) — mira la Guía de Desnormalización para la otra cara del trade-off

1NF — Valores Atómicos

Regla: Cada columna contiene solo valores atómicos (indivisibles). Sin grupos repetidos.

Antes — un grupo repetido en una columna:

order_idcustomerproducts
1AliceApple, Banana, Cherry

Después — solo valores atómicos:

order_idcustomerproduct
1AliceApple
1AliceBanana
1AliceCherry

2NF — Sin Dependencias Parciales

Regla: Todos los atributos no-clave dependen de la clave primaria completa (relevante para claves compuestas).

Antes — depende de parte de la clave:

course_idstudent_idcourse_namestudent_namegrade
CS101S1Intro to CSAliceA

course_name depende solo de course_id; student_name solo de student_id.

Después — todo depende de la clave completa:

Enrollments:

course_idstudent_idgrade
CS101S1A

Courses:

course_idcourse_name
CS101Intro to CS

Students:

student_idstudent_name
S1Alice

3NF — Sin Dependencias Transitivas

Regla: Los atributos no-clave dependen solo de la clave primaria, no de otros atributos no-clave.

Antes — una columna no clave determina otra:

employee_idnamedepartment_iddepartment_namedepartment_head
E1BobD1EngineeringCarol

department_name y department_head dependen de department_id, no de employee_id.

Después — hechos sobre la clave, nada más:

Employees:

employee_idnamedepartment_id
E1BobD1

Departments:

department_iddepartment_namedepartment_head
D1EngineeringCarol

BCNF — Forma Normal de Boyce-Codd

Regla: Para toda dependencia funcional X → Y, X debe ser superclave.

Antes — un determinante que no es clave:

studentcourseprofessor
AliceCS101Prof. Smith
BobCS101Prof. Smith

course → professor, pero course no es superclave.

Después — todo determinante es clave:

Enrollments:

studentcourse
AliceCS101
BobCS101

CourseAssignments:

courseprofessor
CS101Prof. Smith

4NF — Sin Dependencias Multivaluadas

Regla: Sin dependencias multivaluadas excepto sobre superclaves.

Antes — dos hechos independientes por fila:

employeeskilllanguage
AliceJavaEnglish
AliceJavaSpanish
AlicePythonEnglish
AlicePythonSpanish

Skills y languages son hechos multivaluados independientes.

Después — los hechos independientes van separados:

EmployeeSkills:

employeeskill
AliceJava
AlicePython

EmployeeLanguages:

employeelanguage
AliceEnglish
AliceSpanish

5NF — Dependencia de Unión

Regla: Toda dependencia de unión está implicada por las claves candidatas.

Antes — un trío combinable forzado en pares:

agentcompanyproduct
SmithFordTruck
SmithFordCar
SmithToyotaCar
JonesToyotaCar

Después — descompuesto según la dependencia de join:

AgentCompany:

agentcompany
SmithFord
SmithToyota
JonesToyota

AgentProduct:

agentproduct
SmithTruck
SmithCar
JonesCar

CompanyProduct:

companyproduct
FordTruck
FordCar
ToyotaCar

Resumen de Normalización

FormaReglaElimina
1NFValores atómicosGrupos repetidos
2NFDependencia de clave completaDependencias parciales
3NFDependencia solo de claveDependencias transitivas
BCNFDeterminante superclaveAnomalías restantes
4NFSin dependencias multivaluadasValores multi-independientes
5NFDependencias de uniónUniones reconstruibles
Mermaid flowchart LR diagram

Cada paso elimina una clase de redundancia — para donde tu carga de trabajo deje de necesitarlo.

Cuándo Detener la Normalización

  • 3NF/BCNF es el punto práctico para la mayoría de sistemas OLTP
  • 4NF importa cuando tienes atributos verdaderamente multivaluados (raro)
  • 5NF es mayormente teórico para aplicaciones productivas
  • Desnormaliza intencionalmente cuando el rendimiento de lectura importa más que la integridad de escritura — la guía de desnormalización cubre los patrones y las estrategias de sincronización

Errores Comunes

  • Sobrenormalizar hasta 5NF — añade complejidad con mínimo beneficio práctico
  • Subnormalizar hasta 1NF — lleva a anomalías de actualización e inconsistencia de datos
  • Normalizar antes de entender las queries — el esquema debe servir la carga de trabajo
  • Ignorar BCNF — 3NF no maneja todas las anomalías; BCNF es el estándar más estricto

Ejemplo: Pasos de Normalizacion

-- 1NF: Eliminar grupos repetitivos
-- Desnormalizado: orders(id, customer_name, items_csv)
-- 1NF:            orders(id, customer_name, item_name, qty)

-- 2NF: Eliminar dependencias parciales (clave compuesta)
-- 1NF:  order_items(order_id, product_id, product_name, qty)
-- 2NF:  orders(order_id, customer_id)
--       products(product_id, product_name)
--       order_items(order_id, product_id, qty)

-- 3NF: Eliminar dependencias transitivas
-- 2NF:  orders(order_id, customer_id, customer_name, customer_city)
-- 3NF:  orders(order_id, customer_id)
--       customers(customer_id, customer_name, customer_city)

CREATE TABLE customers (
  customer_id SERIAL PRIMARY KEY,
  customer_name VARCHAR(200) NOT NULL,
  customer_city VARCHAR(100)
);

CREATE TABLE orders (
  order_id SERIAL PRIMARY KEY,
  customer_id INT REFERENCES customers(customer_id),
  order_date DATE NOT NULL DEFAULT CURRENT_DATE
);

CREATE TABLE order_items (
  order_id INT REFERENCES orders(order_id),
  product_id INT REFERENCES products(product_id),
  qty INT NOT NULL CHECK (qty > 0),
  PRIMARY KEY (order_id, product_id)
);