La normalización soluciona unos problemas, pero en algunos casos crea otros, sobre todo cuando hablamos de rendimiento. Hoy te vamos a abrir la puerta al arte oscuro (y a veces luminoso) — la desnormalización. Sí, puedes saltarte las reglas de la normalización... ¡pero con cabeza!
La desnormalización es el proceso opuesto a la normalización. Si la normalización divide las tablas en entidades lógicas separadas para minimizar la redundancia, la desnormalización vuelve a juntar los datos para mejorar el rendimiento. Se usa mucho cuando, bajo mucha carga y con consultas complejas frecuentes, los JOINs de muchas tablas empiezan a ralentizar el sistema.
Se puede decir que la desnormalización es un compromiso entre la pureza de los datos y la velocidad de las consultas.
¿Cuándo usar la desnormalización?
Como con cualquier herramienta, es importante saber cuándo la desnormalización tiene sentido. Se usa en estas situaciones:
Consultas frecuentes se vuelven lentas. Cuando un sistema con mucha carga ejecuta las mismas consultas una y otra vez (por ejemplo, informes y agregados), los JOINs de muchas tablas pueden tardar bastante. La desnormalización ayuda a reducir el número de estos JOINs.
Tareas analíticas y estadísticas. En sistemas analíticos (por ejemplo, BI — Business Intelligence) muchas veces se necesita analizar grandes volúmenes de datos. En estos casos, la desnormalización acelera el procesamiento gracias a datos "preparados" de antemano.
Consultas complejas. Si para ejecutar una consulta tienes que unir cinco, diez o incluso más tablas, eso puede ralentizar mucho la base de datos. La desnormalización permite simplificar la estructura de las consultas.
El número de JOINs supera el sentido común. Si tienes consultas con 25 tablas en
JOIN, igual ha llegado el momento de replantearte el enfoque.
Ejemplos de desnormalización
Ejemplo 1: Tienda online. En una base de datos normalizada de una tienda online podríamos tener estas tablas:
clientes— datos de los clientes.pedidos— información sobre los pedidos.productos— datos de los productos.pedido_productos— productos incluidos en el pedido.
La consulta para obtener información podría ser algo así:
SELECT
c.nombre_cliente,
o.fecha_pedido,
p.nombre_producto,
oi.cantidad
FROM
clientes c
JOIN
pedidos o ON c.id_cliente = o.id_cliente
JOIN
pedido_productos oi ON o.id_pedido = oi.id_pedido
JOIN
productos p ON oi.id_producto = p.id_producto
WHERE
c.id_cliente = 42;
Pero ¿qué pasa si nuestra tienda online procesa cientos de miles de pedidos al día? Esta consulta se volverá demasiado lenta por la cantidad de JOINs.
Solución: desnormalización.
Vamos a crear una tabla para la info que más se usa:
CREATE TABLE resumen_pedidos AS
SELECT
c.id_cliente,
c.nombre_cliente,
o.id_pedido,
o.fecha_pedido,
p.id_producto,
p.nombre_producto,
oi.cantidad
FROM
clientes c
JOIN
pedidos o ON c.id_cliente = o.id_cliente
JOIN
pedido_productos oi ON o.id_pedido = oi.id_pedido
JOIN
productos p ON oi.id_producto = p.id_producto;
Ahora, cuando necesitamos los datos, simplemente consultamos resumen_pedidos:
SELECT * FROM resumen_pedidos WHERE id_cliente = 42;
Ejemplo 2: Sistema de analítica. Imagina que trabajas con la base de datos de una empresa que vende entradas para eventos. Hay tablas:
eventos— información sobre los eventos.ventas— datos de las ventas de entradas.
Si los analistas necesitan un informe del ingreso medio por entrada para todos los eventos, la estructura normalizada te obliga a hacer una consulta agregada cada vez:
SELECT
e.nombre_evento,
AVG(s.precio) AS precio_medio_entrada
FROM
eventos e
JOIN
ventas s ON e.id_evento = s.id_evento
GROUP BY
e.nombre_evento;
Esta consulta puede ser bastante lenta, sobre todo si cada venta ocupa millones de filas.
Solución: desnormalización. Creamos una tabla aparte con los datos agregados:
CREATE TABLE resumen_eventos AS
SELECT
e.id_evento,
e.nombre_evento,
COUNT(s.id_venta) AS cantidad_entradas,
SUM(s.precio) AS ingresos_totales,
AVG(s.precio) AS precio_medio_entrada
FROM
eventos e
JOIN
ventas s ON e.id_evento = s.id_evento
GROUP BY
e.id_evento, e.nombre_evento;
Ahora los informes irán mucho más rápido a nivel agregado:
SELECT
nombre_evento,
precio_medio_entrada
FROM
resumen_eventos;
Consecuencias de la desnormalización
La desnormalización, claro, puede acelerar las consultas, pero no es una varita mágica que lo soluciona todo. Esto es con lo que te puedes topar si decides tirar por este camino.
Lo primero — duplicación de datos. Cuando la misma info se guarda en varios sitios, el tamaño de la base crece rápido y se vuelve más difícil de manejar.
Lo segundo — ahora actualizar los datos es más complicado. Imagina que tienes los datos de un cliente en la tabla clientes, y otra copia en la tabla resumen_pedidos. Si el cliente cambia de nombre o dirección, tienes que acordarte de actualizarlo en los dos sitios. Si te olvidas — ya tienes un error, porque los datos ya no coinciden.
Lo tercero — con tanta redundancia es fácil liarse y cometer errores. Es como con diferentes versiones de un mismo documento — a veces cuesta saber cuál es la buena.
Y por último, mantener y evolucionar una base así es más difícil. Vas a tener que escribir triggers o scripts especiales para que todas las copias de los datos estén sincronizadas. Es curro extra para los developers.
En resumen, la desnormalización es una herramienta que hay que usar con cabeza, sabiendo bien sus pros y contras.
GO TO FULL VERSION