Cuando normalizamos los datos a la perfección, cada tabla se vuelve lo más compacta posible y la información en ella sigue estrictamente un solo principio. Pero para hacer consultas reales (por ejemplo, "¿Qué estudiantes están inscritos en el curso de SQL?") puede que tengas que juntar un montón de tablas. Cuantas más tablas, más complicadas las consultas y más la base de datos "pica pala".
Seguro que ya conoces los JOIN de las lecciones anteriores. Aquí tienes un ejemplo de consulta que podrías necesitar con una base de datos bien diseñada:
SELECT students.name, courses.title
FROM students
JOIN enrollments ON students.id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.id
WHERE courses.title = 'SQL';
Suena fácil, pero por detrás el servidor hace un curro infernal: lee cada tabla, une los datos, filtra... ¿Y si las tablas son enormes? Es lógico pensar que el rendimiento va a caer.
Batallitas: normalización vs velocidad
Por suerte (¿o por desgracia?), en la vida real las bases de datos son un compromiso. La normalización total asegura la integridad de los datos, pero ralentiza las consultas complejas. Si la base de datos se va a usar para analítica e informes, a veces es mejor desnormalizarla. Es como cambiar 10 cajitas pequeñas por un solo baúl grande: sacar los datos es más rápido, pero volver a ordenarlos es más complicado.
¿Cuándo puedes "relajarte" con la normalización?
Hay escenarios donde la desnormalización es mejor:
Agregados usados a menudo
Por ejemplo, imagina que el sistema hace consultas diarias para contar cuántos estudiantes hay en cada curso. En una estructura normalizada, tendrías que hacerJOIN y
COUNT() todo el rato. En vez de eso, puedes añadir a la tabla "Courses" una columna
student_count, que se actualiza automáticamente al añadir o borrar registros.
-- Columna desnormalizada
UPDATE courses
SET student_count = (
SELECT COUNT(*)
FROM enrollments
WHERE enrollments.course_id = courses.id
);
Informes que se hacen todo el tiempo
Si tu cliente quiere cada día un informe tipo "¿Quién, dónde, cuándo compró?", es más fácil guardar una tabla desnormalizada con filas ya preparadas como "Nombre del cliente, producto, fecha". La tabla será más grande, pero la velocidad de consulta sube.
Muchas lecturas, pocas escrituras
Cuando la base de datos se usa sobre todo para leer (por ejemplo, analítica), vale la pena sacrificar normalización por velocidad.
Minimizar joins en relaciones complejas
Si entre las tablas hay relaciones en varios niveles (nested), y elJOIN se vuelve una pesadilla, quita algunos niveles de normalización.
Ejemplo: ¿cómo acelera la desnormalización?
Tenemos tablas normalizadas de una tienda online:
Tabla products |
Tabla orders |
Tabla order_items |
|---|---|---|
| id | id | id |
| name | date | order_id |
| price | customer_id | product_id |
| quantity |
Cada pedido (orders) consiste en filas de pedido (order_items). Vamos a calcular cuánto dinero ha ganado la tienda:
SELECT SUM(order_items.quantity * products.price) AS total_revenue
FROM order_items
JOIN products ON order_items.product_id = products.id;
El proceso de unir order_items y products ralentiza la consulta cuando hay muchos datos.
Estructura desnormalizada
Ahora imagina que en la tabla order_items hay una columna "extra" total_price (desnormalización):
Tabla order_items |
|---|
| id |
| order_id |
| product_id |
| quantity |
| total_price |
Ahora la consulta es trivial:
SELECT SUM(total_price) AS total_revenue
FROM order_items;
Así evitamos el JOIN y aceleramos la ejecución.
Ejercicio práctico: optimiza la base "Ventas"
Dado: tablas normalizadas
Tabla products |
Tabla sales |
|---|---|
| id | id |
| name | product_id |
| price | date |
| quantity |
Objetivo: acelerar consultas frecuentes tipo "¿Cuánto hemos ganado en cada producto?".
Paso 1: añade la columna total_price a la tabla sales:
ALTER TABLE sales ADD COLUMN total_price NUMERIC;
Paso 2: rellena esa columna con los datos existentes:
UPDATE sales
SET total_price = quantity * (
SELECT price
FROM products
WHERE products.id = sales.product_id
);
Paso 3: haz consultas más rápidas:
SELECT product_id, SUM(total_price) AS total_revenue
FROM sales
GROUP BY product_id;
¡Pero! La desnormalización tiene un precio
Ya sabes que "más rápido" no siempre es "mejor". Con la desnormalización aparecen problemas:
Almacenamiento redundante
La columnatotal_price es una copia de datos que ocupa espacio extra.
Actualizaciones más complicadas
Si el precio de un producto cambia en la tabla products, tienes que actualizar la columna total_price a mano. Esto puede causar inconsistencias.
Anomalías al insertar, actualizar o borrar
La información se puede "desincronizar" fácilmente si olvidas actualizar los datos desnormalizados. Por ejemplo, si cambia el precio de un producto, no se actualiza automáticamente.
Equilibrio: ¿cómo encontrar el punto justo?
Elige qué es más importante: ¿rendimiento o estructura? Si la base se lee mucho, adáptate a las consultas.
Desnormaliza solo donde haga falta. Por ejemplo, solo para cifras clave e informes.
Automatiza la actualización de los datos desnormalizados. Usa triggers o tareas para evitar inconsistencias.
GO TO FULL VERSION