Ha surgido un nuevo requisito en una antigua base de código, que básicamente permite la comunicación directa (interna) entre dos clases de usuarios que anteriormente no estaban directamente relacionadas (almacenadas en tablas diferentes con un esquema completamente diferente y, lamentablemente, el código apenas es consciente de OO, mucho menos diseñado, por lo que no hay clase principal). Dado que estamos dispuestos a colgar una bolsa en esta configuración anterior que nunca consideró esta funcionalidad, no hay garantía de que no haya colisiones PK; dado el conjunto de datos en uso, está prácticamente garantizado que HAY.
Entonces, la solución parece obvia: mátala con fuego y reescribe todo el desorden de una tabla de mapeo. Obtuve dos instrucciones sobre las posibles formas de implementar el mapa, pero no soy un DBA, por lo que no estoy seguro de si hay algunos pros y contras que me haya perdido.
En aras de aclarar la abstracción, considere tres grupos de datos de usuarios dispares: profesores, administración, estudiantes (No, esta no es una tarea. ¡Promesa!)
Mapeo 1
(professor_id, admin_id y student_id son claves foráneas para sus tablas respectivas)
| mailing_id (KEY) | professor_id | admin_id | student_id |
-------------------------------------------------------
| 1001 | NULL | 87 | NULL |
| 1002 | 123 | NULL | NULL |
| 1003 | NULL | NULL | 123 |
El +/- a este enfoque parece bastante pesado en los contras:
- Dos campos "desperdiciados" por fila
- Viola 2NF
- Vulnerable para insertar / actualizar anomalías (una fila con solo 0-1 conjunto de campos NULL, por ejemplo)
Sin embargo, los profesionales no carecen de sus propios méritos:
- El mapeo se puede lograr con una sola búsqueda
- Determine fácilmente los datos de "fuente" para un usuario determinado desde el mailing_id
A decir verdad, en mi interior, no me gusta esta idea en absoluto.
Mapeo 2
(suponga que MSG_ * son constantes definidas, tipos de enumeración u otro identificador adecuado)
| mailing_id (KEY) | user_type (UNIQUE1) | internal_id (UNIQUE2)|
------------------------------------------------------------------
| 1001 | MSG_ADMIN | 87 |
| 1002 | MSG_PROF | 123 |
| 1003 | MSG_STUDENT | 123 |
Con esta configuración, y un índice compuesto único de {user_type, internal_id} las cosas se vuelven mucho más limpias, se mantiene 3NF y el código de la aplicación no tiene que verificar las anomalías de E / S.
En el lado negativo, hay una pequeña pérdida de transparencia al determinar las tablas de origen del usuario que deben manejarse fuera de la base de datos, lo que básicamente equivale a una asignación a nivel de aplicación de los valores de tipo de usuario a las tablas. En este momento, me estoy inclinando (bastante fuerte) hacia este segundo mapeo, ya que la desventaja es bastante menor.
PERO soy dolorosamente consciente de mis propias limitaciones, y estoy seguro de que probablemente haya perdido ventajas o tropiezos en ambas direcciones, así que recurro a mentes más sabias que las mías.
fuente
Respuestas:
Tu segunda idea es la correcta. Este enfoque le permite hacer todo el mapeo que necesita hacer para integrar sus tres espacios clave en colisión.
Es importante destacar que permite que la base de datos imponga la mayor parte de la coherencia que necesita tener usando restricciones declarativas .
Ya tiene más código del que desea tener, así que no agregue más código del necesario para mantener la coherencia de su lista de claves integrada. Deje que su motor de base de datos haga lo que fue creado para hacer.
El "niño problemático" que le produce molestias en Mapping 2 es la
USER_TYPE
columna. Esta columna es importante porque la necesita para asegurarse de queINTERNAL_ID
solo aparezca como máximo una vez por tipo de usuario. La única vez que necesita un código que sea conscienteUSER_TYPE
es el código que se inserta y elimina de su tabla de mapeo. Esto se puede localizar bastante bien. Supongo que creará un único punto en su código donde se mantiene el contenido de la tabla de mapeo. Una columna adicional en este lugar donde se escriben los datos no es gran cosa. Lo que realmente desea evitar es agregar la columna adicional en todas partes donde se leen los datos .El código en sus sub-aplicaciones que necesita usar el mapeo puede ser felizmente ignorante del
USER_TYPE
simple al dar a cada sub-aplicación una vista que filtre los mapeos hasta el tipo de usuario específico de la aplicación.fuente
Por experiencia, mi recomendación es elegir la coherencia sobre la elegancia o la 'mejor práctica'. Es hacer coincidir el diseño existente e ir con TRES tablas de correo (una para cada rol) con una
mailing_id, user_id
estructura de campo simple .Es poco elegante pero tiene algunas ventajas ...
Estoy seguro de que muchos otros no estarán de acuerdo con este enfoque, pero los objetivos principales de la normalización y las mejores prácticas son hacer que el código sea más coherente para que sea más fácil de seguir y depurar ... y, obviamente, no es factible poner a cero toda la base de código.
fuente