Laboratorio 3: Normalización e Integridad en Aletza
Laboratorio 3: Normalización e Integridad en Aletza
Objetivo
Aplicar los conceptos de normalización (1FN, 2FN, 3FN, BCNF) y restricciones de integridad (dominio, entidad, referencial) al caso de estudio Aletza, sin escribir código SQL aún. El estudiante analizará el modelo de datos existente, identificará posibles anomalías, propondrá mejoras y reflexionará sobre las decisiones de diseño que garantizan la consistencia de los datos en un sistema real.
1. Introducción Teórica Breve
La normalización es el proceso de organizar los atributos en tablas para eliminar redundancias y prevenir anomalías de inserción, actualización y eliminación. Se basa en dependencias funcionales y aplica reglas conocidas como formas normales.
- 1FN: Atributos atómicos, sin grupos repetitivos.
- 2FN: En tablas con clave compuesta, todos los atributos no clave dependen completamente de la clave.
- 3FN: Eliminar dependencias transitivas (atributos no clave que dependen de otros atributos no clave).
- BCNF: Toda dependencia funcional no trivial tiene como determinante una superclave.
La integridad de datos se garantiza mediante restricciones:
- Dominio:
NOT NULL,CHECK, tipos de datos. - Entidad:
PRIMARY KEY,UNIQUE. - Referencial:
FOREIGN KEYcon acciones (CASCADE,SET NULL, etc.).
2. Actividades
Actividad 1: Identificar violaciones de normalización en el modelo actual de Aletza
El modelo inicial de Aletza (propuesto en el caso de estudio) incluye las siguientes tablas:
Tabla: usuarios
| Campo | |————-| | id | | username | | email | | creado_en |
Tabla: perfiles_voz
| Campo | |—————-| | id | | usuario_id | | palabra_magica | | vector_voz | | muestras_tomadas| | estado | | creado_en |
Tabla: sesiones
| Campo | |—————-| | id | | usuario_id | | token | | canal | | iniciada_en | | ultima_actividad| | expira_en |
Tabla: mensajes
| Campo | |————-| | id | | sesion_id | | remitente_id| | contenido | | modalidad | | metadata_ia | | enviado_en |
Tabla: logs_ejecucion
| Campo | |—————-| | id | | mensaje_id | | modulo | | tiempo_ejecucion_ms | | exito | | error | | ejecutado_en |
Analiza cada tabla y responde:
- ¿Alguna tabla viola la 1FN? Justifica.
- ¿Hay tablas con clave compuesta? Si es así, ¿puede haber dependencias parciales que violen 2FN? Examina especialmente
logs_ejecucion. - ¿Existen dependencias transitivas en alguna tabla? Por ejemplo, ¿algún atributo no clave determina otro atributo no clave?
- ¿La tabla
perfiles_vozestá en 3FN? Considera quepalabra_magicasiempre es “aletza”. ¿Podría almacenarse en otro lugar?
Solucionario Actividad 1: Identificar violaciones de normalización
- 1FN: Todas las tablas cumplen 1FN porque cada columna almacena valores atómicos. No hay grupos repetidos.
perfiles_voz.vector_vozes JSONB, pero es un valor único (un documento JSON), no una lista repetitiva de valores simples. Aunque JSONB puede contener arrays, se considera un valor compuesto pero atómico desde la perspectiva del modelo relacional (es un tipo de datos). En la práctica, es aceptable porque no se almacenan múltiples valores en una columna con separadores. Si dentro del JSON hubiera un array de muestras individuales, eso sí violaría 1FN. En nuestro diseño actual,vector_vozalmacena un único embedding final, no las 10 muestras.
- Clave compuesta: Ninguna tabla tiene clave primaria compuesta.
logs_ejecuciontieneidcomo PK simple, por lo que no aplica 2FN. Si la clave fuera(mensaje_id, modulo), entonces sí habría que verificar dependencias parciales, pero no es el caso.
- Dependencias transitivas:
- En
sesiones,usuario_iddetermina al usuario, pero no hay otros atributos no clave que dependan de otro no clave. - En
mensajes,sesion_iddetermina al usuario implícitamente (a través de la sesión), pero no hay atributos no clave que dependan de otro no clave dentro de la misma tabla. - En
logs_ejecucion,mensaje_iddetermina el mensaje, pero no hay atributos adicionales dependientes. - En
perfiles_voz,palabra_magicaes siempre “aletza”. Esto podría considerarse redundante, pero no es una dependencia transitiva porque no hay otra columna que la determine.
- En
- Perfiles_voz en 3FN: La tabla está en 3FN porque todos los atributos no clave (
palabra_magica,vector_voz,muestras_tomadas,estado,creado_en) dependen directamente de la claveid(o deusuario_idsi consideramos queusuario_idtambién es clave candidata). No hay dependencias transitivas. Sin embargo, la columnapalabra_magicaes constante para todos los registros, lo que podría ser una redundancia que se puede eliminar moviéndola a una tabla de configuración, pero no es una violación de forma normal.
Actividad 2: Normalización de perfiles_voz
Actualmente perfiles_voz almacena las muestras de voz como un único campo vector_voz (JSONB) que contiene el embedding biométrico después de las 10 muestras. Sin embargo, el proceso de enrollment requiere almacenar cada muestra individual para poder entrenar el perfil.
Pregunta:
¿Cómo modificarías el modelo para registrar las 10 muestras individuales? Propón un esquema normalizado que respete 1FN y 2FN. ¿Qué nuevas tablas crearías y cuáles serían sus claves?
Solucionario actividad 2: Normalización de perfiles_voz
Para registrar cada muestra individual, se necesita una tabla separada:
muestra_voz (id, perfil_id, muestra_numero, vector_muestra, creado_en)perfiles_vozse simplifica:(id, usuario_id, estado, creado_en)muestras_tomadasse puede derivar contando las muestras, pero puede mantenerse como atributo derivado (o no).
La nueva tabla muestra_voz tiene clave primaria id (o (perfil_id, muestra_numero)). La clave foránea perfil_id referencia a perfiles_voz.
Esto cumple 1FN (cada muestra es una fila) y 2FN (la clave es simple o compuesta, pero no hay dependencias parciales).
Actividad 3: Dependencias funcionales en sesiones
Supón que se añade un campo nombre_canal a sesiones para almacenar el nombre descriptivo del canal (ej. “Telegram Bot”, “Web App”, “iOS App”). Observa que canal es un código abreviado (‘telegram’, ‘web’, ‘app’) y nombre_canal sería su descripción.
- Identifica la dependencia funcional que surge.
- ¿Esta dependencia viola alguna forma normal? ¿Cuál y por qué?
- Propón una solución normalizada.
Solucionario actividad 3: Dependencias funcionales en sesiones
- Dependencia funcional:
canal → nombre_canal(el código abreviado determina el nombre descriptivo). - Violación: Si
nombre_canalse añade asesiones, se introduce una dependencia transitiva sicanalno es clave.canalno es clave primaria ni candidata (puede haber muchas sesiones con el mismo canal). Entonces,nombre_canaldepende decanal, que no es superclave. Esto viola 3FN (y también BCNF). - Solución: Crear una tabla
canalcon(codigo, nombre)y ensesionesmantener solocanalcomo FK. Esto normaliza.
Actividad 4: Restricciones de integridad (dominio y entidad)
Define restricciones de dominio apropiadas para los siguientes campos en el modelo de Aletza. No escribas código, pero describe qué tipo de restricción usarías y los valores permitidos.
modalidadenmensajesestadoenperfiles_vozmuestras_tomadasenperfiles_voz(rango)canalensesionesexitoenlogs_ejecuciontokenensesiones(unicidad)
Además, ¿qué restricción de entidad (clave primaria) asegura que no haya dos usuarios con el mismo email? ¿Y con el mismo username?
Solucionario actividad 4: Restricciones de integridad
modalidad:CHECK (modalidad IN ('texto', 'audio', 'imagen', 'video'))estado:CHECK (estado IN ('incompleto', 'completo'))muestras_tomadas:CHECK (muestras_tomadas BETWEEN 0 AND 10)canal:CHECK (canal IN ('telegram', 'web', 'app'))exito:BOOLEAN(ya restringido por tipo)token:UNIQUE(además deNOT NULL)-
Entidad:
PRIMARY KEYen cada tabla asegura unicidad. Para email y username:UNIQUEenusuarios.
Actividad 5: Integridad referencial en el proceso de enrollment
El proceso de enrollment requiere que un usuario registre 10 muestras de voz. El modelo actual almacena el resultado final en perfiles_voz y el campo muestras_tomadas cuenta cuántas se han recibido.
Reflexiona:
- Si se eliminara un usuario, ¿qué debería ocurrir con su perfil de voz? ¿Y con sus sesiones y mensajes? ¿Qué acción referencial (
CASCADE,SET NULL,RESTRICT) sería adecuada en cada FK? - Durante el enrollment, ¿cómo se garantiza que no se excedan las 10 muestras? ¿Es una restricción de dominio o una regla de negocio que requiere lógica adicional?
- Propón una regla de negocio (conceptualmente) para evitar que un usuario complete el enrollment si no ha enviado exactamente 10 muestras.
Solucionario actividad 5: Integridad referencial en el enrollment
- Eliminación de usuario: Debería eliminarse en cascada sus perfiles de voz, sesiones, mensajes y logs. Las FK deberían tener
ON DELETE CASCADE. - Control de 10 muestras: Es una regla de negocio que puede implementarse con un trigger o en la lógica de la aplicación. No es una restricción declarativa simple porque implica contar registros de otra tabla. Se puede usar un
CHECKcon una subconsulta en algunos SGBD, pero no es común; mejor se implementa con un trigger que impida la inserción de la muestra 11. -
Evitar completar sin 10 muestras: Se puede definir que el
estadosolo pueda cambiar a ‘completo’ cuandomuestras_tomadas = 10. Esto podría ser un trigger o una restricciónCHECKque valide la condición en la actualización.
Actividad 6: Anomalías de actualización en un modelo desnormalizado
Imagina que en lugar de tener tablas separadas para usuarios y perfiles_voz, se hubiera optado por guardar toda la información en una sola tabla usuarios_con_perfil con campos: id, username, email, vector_voz, muestras_tomadas, estado, palabra_magica.
-
¿Qué anomalías de actualización podrían ocurrir si un usuario cambia su email? (Considera que el email aparece una sola vez por usuario, pero el problema es otro: en este diseño, el email se almacena una sola vez, pero si hubiera múltiples filas por usuario, sería peor. En realidad, la anomalía sería la redundancia de otros datos si se repite el perfil, pero aquí hay una fila por usuario, no hay múltiples filas. Sin embargo, el diseño sigue siendo redundante porque el perfil de voz es un solo registro por usuario, pero podría tener sentido. La pregunta busca identificar que la desnormalización no siempre es mala, pero debemos pensar en si hubiera repetición).
Mejor replantea: supón que en lugar de una tabla
perfiles_vozseparada, los vectores de voz se almacenan en la misma tablausuarios. ¿Qué problemas de integridad podrían surgir si un usuario tuviera varios perfiles (por ejemplo, por actualización de voz) y no se separara?Reformula para reflejar una desnormalización típica: en lugar de
perfiles_vozcon FK, se guardavector_vozenusuarios. Pero el proceso de enrollment requiere almacenar muestras individuales. Si se guardaran todas las muestras en una columna repetitiva, violaría 1FN.La actividad busca que el estudiante identifique las ventajas de tener tablas separadas para manejar el ciclo de vida del perfil.
Enunciado concreto:
Supón que, por simplicidad, se decide eliminar la tabla perfiles_voz y añadir los campos vector_voz, muestras_tomadas, estado y palabra_magica directamente en usuarios.
- ¿Qué ocurre si un usuario necesita actualizar su perfil de voz (por ejemplo, porque su voz cambia con el tiempo)?
- ¿Cómo afecta esto al historial de autenticaciones?
- ¿Qué anomalías de actualización o eliminación podrían presentarse si más adelante se quisiera guardar un histórico de perfiles?
Solucionario actividad 6: Anomalías de actualización en un modelo desnormalizado
Si se guarda todo en una sola tabla usuarios con los campos del perfil de voz:
- Actualización de perfil: Si el usuario necesita reentrenar su voz (por ejemplo, después de una enfermedad), se perdería el perfil anterior. No habría historial.
- Historial de autenticaciones: No se podría saber con qué perfil se autenticó en el pasado si el perfil cambia.
- Anomalías de actualización: Si más adelante se quisiera mantener un histórico de perfiles (por ejemplo, para auditoría), sería necesario duplicar los datos del usuario en varias filas, lo que violaría 1FN o causaría redundancia. La solución es tener tablas separadas que permitan múltiples perfiles a lo largo del tiempo.
Actividad 7: Dependencias multivaluadas y 4NF
En el sistema Aletza, cada mensaje puede tener varios módulos de IA aplicados, y cada módulo genera un registro en logs_ejecucion. Actualmente, logs_ejecucion tiene una clave primaria id simple, y cada fila representa un módulo.
Supón que un mensaje también pudiera estar asociado a varios destinatarios (por ejemplo, un mensaje enviado a un grupo). Si se añadiera una tabla mensaje_destinatario con (id_mensaje, id_usuario), ¿se violaría alguna forma normal? Explica.
Solucionario actividad 7: Dependencias multivaluadas y 4NF
Si se añade mensaje_destinatario con (id_mensaje, id_usuario), se introduce una dependencia multivaluada: un mensaje puede tener varios destinatarios independientemente de otros atributos. Si el mensaje también tuviera, por ejemplo, varias etiquetas (categorías), y ambas fueran independientes, se violaría 4NF. En nuestro caso, con solo una relación multivalorada (destinatarios), no hay problema, pero si más adelante se añadiera otra tabla similar (ej. mensaje_etiqueta), habría que considerar si las dos son independientes. Si lo son, la combinación en una sola tabla generaría redundancia y violaría 4NF.