Mi experiencia es más en programación web que en administración de bases de datos, así que corríjame si estoy usando la terminología incorrecta aquí. Estoy tratando de encontrar la mejor manera de diseñar la base de datos para una aplicación que codificaré.
La situación: tengo Informes en una tabla y Recomendaciones en otra tabla. Cada informe puede tener muchas recomendaciones. También tengo una tabla separada para palabras clave (para implementar el etiquetado). Sin embargo, quiero tener solo un conjunto de palabras clave que se apliquen tanto a los Informes como a las Recomendaciones para que la búsqueda de palabras clave le brinde informes y recomendaciones como resultados.
Aquí está la estructura con la que comencé:
Reports
----------
ReportID
ReportName
Recommendations
----------
RecommendationID
RecommendationName
ReportID (foreign key)
Keywords
----------
KeywordID
KeywordName
ObjectKeywords
----------
KeywordID (foreign key)
ReportID (foreign key)
RecommendationID (foreign key)
Instintivamente, siento que esto no es óptimo y que debería hacer que mis objetos etiquetables hereden de un padre común, y que ese comentario sea etiquetado, lo que daría la siguiente estructura:
BaseObjects
----------
ObjectID (primary key)
ObjectType
Reports
----------
ObjectID_Report (foreign key)
ReportName
Recommendations
----------
ObjectID_Recommendation (foreign key)
RecommendationName
ObjectID_Report (foreign key)
Keywords
----------
KeywordID (primary key)
KeywordName
ObjectKeywords
----------
ObjectID (foreign key)
KeywordID (foreign key)
¿Debo ir con esta segunda estructura? ¿Me estoy perdiendo alguna preocupación importante aquí? Además, si voy con el segundo, ¿qué debo usar como nombre no genérico para reemplazar "Objeto"?
Actualizar:
Estoy usando SQL Server para este proyecto. Es una aplicación interna con una pequeña cantidad de usuarios no concurrentes, por lo que no preveo una gran carga. En términos de uso, las palabras clave probablemente se usarán con moderación. Es prácticamente solo para fines de informes estadísticos. En ese sentido, cualquier solución que elija probablemente solo afectará a los desarrolladores que necesiten mantener este sistema en el futuro ... pero pensé que es bueno implementar buenas prácticas siempre que pueda. ¡Gracias por toda la perspectiva!
fuente
Respuestas:
El problema con su primer ejemplo es la tabla de tres enlaces. ¿Eso requerirá que una de las claves foráneas en el informe o las recomendaciones sea siempre NULL para que las palabras clave se vinculen solo de una manera u otra?
En el caso de su segundo ejemplo, la unión desde la base a las tablas derivadas ahora puede requerir el uso del selector de tipo o uniones IZQUIERDA dependiendo de cómo lo haga.
Dado eso, ¿por qué no hacerlo explícito y eliminar todos los NULL y LEFT JOIN?
En este escenario, cuando agrega algo más que necesita ser etiquetado, simplemente agrega la tabla de entidades y la tabla de enlaces.
Luego, los resultados de su búsqueda se verán así (vea si todavía hay una selección de tipo en curso y los convierte en genéricos en el nivel de resultados del objeto si desea una sola lista de resultados):
No importa qué, en algún lugar habrá selección de tipo y algún tipo de ramificación.
Si observa cómo haría esto en su opción 1, es similar pero con una declaración CASE o uniones izquierdas y una COALESCE. A medida que expande su opción 2 con más elementos vinculados, debe seguir agregando más IZQUIERDAS IZQUIERDAS donde normalmente no se encuentran elementos (un objeto vinculado solo puede tener una tabla derivada que sea válida).
No creo que haya algo fundamentalmente incorrecto con su opción 2, y en realidad podría hacer que parezca esta propuesta con un uso de vistas.
En su opción 1, tengo algunas dificultades para ver por qué optó por la tabla de tres enlaces.
fuente
Primero, tenga en cuenta que la solución ideal depende en cierta medida del RDBMS que utilice. Voy a dar entonces la respuesta estándar y la respuesta específica de PostgreSQL.
Respuesta normalizada, estándar
La respuesta estándar es tener dos tablas de unión.
Supongamos que tenemos nuestras tablas:
Este enfoque sigue todas las reglas de normalización estándar y no rompe los principios tradicionales de normalización de la base de datos. Debería funcionar en cualquier RDBMS.
Respuesta específica de PostgreSQL, diseño N1NF
Primero, una palabra sobre por qué PostgreSQL es diferente. PostgreSQL admite varias formas muy útiles de usar índices sobre matrices, sobre todo usando lo que se conoce como índices GIN. Estos pueden beneficiar bastante el rendimiento si se usan correctamente aquí. Debido a que PostgreSQL puede "alcanzar" los tipos de datos de esta manera, el supuesto básico de atomicidad y normalización es algo problemático de aplicar rígidamente aquí. Por esta razón, mi recomendación sería romper la regla de atomicidad de la primera forma normal y confiar en los índices GIN para un mejor rendimiento.
Una segunda nota aquí es que, si bien esto proporciona un mejor rendimiento, agrega algunos dolores de cabeza porque tendrá que realizar un trabajo manual para lograr que la integridad referencial funcione correctamente. Entonces, la compensación aquí es el rendimiento para el trabajo manual.
Ahora tenemos que agregar desencadenantes para garantizar que las palabras clave se administren correctamente.
En segundo lugar, tenemos que decidir qué hacer cuando se elimina una palabra clave. Tal como está ahora, una palabra clave eliminada de la tabla de palabras clave no se aplicará en cascada a los campos de palabras clave. Tal vez esto sea deseable y tal vez no. Lo más simple es restringir la eliminación siempre y esperar que maneje manualmente este caso si aparece (use un disparador para seguridad aquí). Otra opción puede ser reescribir cada valor de palabras clave donde exista la palabra clave para eliminarla. Una vez más, un disparador sería la forma de hacerlo también.
La gran ventaja de esta solución es que puede indexar búsquedas muy rápidas por palabra clave, y puede extraer todas las etiquetas sin una unión. La desventaja es que eliminar una palabra clave es una molestia y no funcionará bien incluso en un buen día. Esto puede ser aceptable porque es un evento raro y podría ser enviado a un proceso en segundo plano, pero es una compensación que vale la pena entender.
Criticando su primera solución
El verdadero problema con su primera solución es que no tiene una clave posible en ObjectKeywords. En consecuencia, tiene un problema en el que no puede garantizar que cada palabra clave se aplique a cada objeto solo una vez.
Su segunda solución es un poco mejor. Si no le gustan las otras soluciones ofrecidas, le sugiero que lo haga. Sin embargo, sugeriría deshacerse de keyword_id y simplemente unirse al texto de la palabra clave. Eso elimina una unión sin desnormalizar.
fuente
Sugeriría dos estructuras separadas:
De esta forma, no tiene todos los identificadores de entidad posibles en la misma tabla (que no es muy escalable, y podría ser confuso), y no tiene una tabla con un "ID de objeto" genérico que deba desambiguar en otro lugar usando la
base_object
tabla, que funcionará, pero creo que complica el diseño.fuente
BaseObjects
tabla en mi primera lectura y pensé que estaba viendo una descripción de una tabla dondeobject_id
puede apuntar a una ID en cualquier tabla.En mi experiencia, esto es lo que puedes hacer.
Y para la relación entre palabras clave, informes y recomendaciones, puede hacer una de dos opciones: Opción A:
Esto permite una relación directa de Informes a Recomendaciones, a Palabras clave y finalmente a Palabras clave. Opcion B:
La opción A es la más fácil de aplicar y administrar, ya que tendrá las restricciones de la base de datos para manejar la integridad de los datos y no permitirá la inserción de datos no válidos.
La opción B, aunque requiere un poco más de trabajo, ya que tendrá que codificar la identificación de la relación. Es más flexible a largo plazo, si por casualidad en algún momento en el futuro necesita agregar palabras clave a otro elemento que no sea el informe o la recomendación, solo necesita agregar la identificación y usar directamente la tabla.
fuente