mysql - how - normalization rules in sql
normalización innecesaria (11)
Aquí está el trato. Cada vez que crees algo, quieres asegurarte de que tenga espacio para crecer. Desea intentar anticipar proyectos futuros y futuros avances para su programa. En este escenario, tiene razón al decir que actualmente no es necesario agregar una tabla de personas que solo contenga 1 campo (sin contar la ID, suponiendo que tiene un campo de ID int y un nombre de persona). Sin embargo, en el futuro, es posible que desee tener otros atributos para dichas personas, como el nombre, apellido, dirección de correo electrónico, fecha de agregado, etc.
Si bien la sobrenormalización es ciertamente dañina, personalmente crearía otra tabla más grande para mantener a la persona con campos adicionales para que pueda agregar fácilmente nuevas características en el futuro.
Mi amigo y yo estamos construyendo un sitio web y tenemos un gran desacuerdo. El núcleo del sitio es una base de datos de comentarios sobre "personas". Básicamente, las personas pueden ingresar comentarios y pueden ingresar a la persona de quien se trata el comentario. Luego, los espectadores pueden buscar en la base de datos las palabras que están en el comentario o partes del nombre de la persona. Es completamente generado por el usuario. Por ejemplo, si alguien desea publicar un comentario en una versión mal escrita del nombre de una persona, puede hacerlo, y eso está bien. Por lo tanto, puede haber varias ortografías de diferentes personas enumeradas como varias entradas diferentes (algunas con segundo nombre, algunas con apodo, otras mal redactadas, etc.), pero todo está bien. No nos importa si las personas hacen comentarios sobre personas al azar o personas imaginarias.
De todos modos, el problema es cómo estamos estructurando la base de datos. En este momento, es solo una tabla con la identificación del comentario como la clave principal, y luego hay un campo para la ''persona'' del comentario:
ID de comentario - comentario - persona
1 - "él es raro" - John Smith
2 - "chica maloliente" - Jenny
3 - "gay" - John Smith
4 - "Me debe $ 20" - Jennyyyyyyyyy
Todo está funcionando bien. Usando la base de datos, puedo crear páginas que enumeran todos los ''comentarios'' para una ''persona'' en particular. Sin embargo, está obsesionado con que la base de datos no esté normalizada. Leí acerca de la normalización y aprendí que estaba equivocado. La tabla ES actualmente normalizada, porque la ID del comentario es única y dicta el ''comentario'' y la ''persona''. Ahora él es insistente en que ''la persona'' debería tener su PROPIA mesa porque es una ''cosa''. No creo que sea necesario, porque aunque ''persona'' realmente es el contenedor más grande (una ''persona'' puede tener muchos ''comentarios'' sobre ellos), la base de datos parece funcionar bien con ''persona'' como un atributo de la identificación del comentario. Utilizo varias llamadas PHP para diferentes selecciones SQL para hacer que parezca mágicamente más sofisticado en la salida y la forma diferente en que el usuario puede buscar y ver los resultados, pero en realidad, la configuración es bastante simple. Ahora estoy permitiendo que los usuarios clasifiquen los comentarios con los pulgares arriba y con los pulgares hacia abajo, y conservo un ''puntaje'' como otro campo en la misma tabla.
Siento que actualmente no hay necesidad de tener una tabla separada solo para entradas únicas de ''persona'' porque las ''personas'' no tienen su propia ''puntuación'' o ninguno de sus propios atributos. Solo los comentarios lo hacen. Mi amigo es tan insistente que es necesario para la eficiencia. Finalmente dije, "OK, si quieres que cree una tabla separada y que ''persona'' sea su propio campo, entonces ¿cuál sería el segundo campo? Porque si una tabla tiene solo una columna, parece inútil. Estoy de acuerdo que luego podemos crear la necesidad de darle a ''persona'' su propia mesa, pero podemos lidiar con eso entonces ". Luego dijo que las cadenas no pueden ser claves primarias, y que convertiríamos las ''personas'' en la tabla actual en números, y los números serían la clave principal en la nueva tabla ''persona''. Para mí, esto parece innecesario y haría que la tabla actual sea más difícil de leer. También piensa que será imposible crear la segunda tabla más adelante, y que debemos anticipar ahora que podríamos necesitarla para algo más adelante.
¿Quién tiene la razón?
Bueno, hay dos escuelas de pensamiento. Una dice: crea tu modelo de datos de la manera más normalizada posible, luego des-normaliza si necesitas más eficiencia. El otro es básicamente "hacer el trabajo mínimo necesario para el trabajo, luego cambiarlo a medida que cambien sus requisitos". También conocido como YAGNI (No lo va a necesitar).
Todo depende de dónde veas que va esto. Si esto es todo lo que será, entonces su enfoque probablemente esté bien. Si intenta mejorarlo con nuevas características con el tiempo, entonces su amigo tiene razón.
Crear una nueva tabla para persona y usar la clave de esa tabla en lugar del atributo persona no tiene nada que ver con la normalización. Puede ser una buena idea por otras razones, pero hacerlo no hace que la base de datos esté "más normalizada" que no hacerlo. Así que tienes razón: en lo que respecta a la normalización, no es necesario crear otra tabla.
La normalización se trata de dependencias funcionales (FD). Debe identificar todos los FD que existen entre los atributos de su modelo de datos antes de que se pueda normalizar por completo.
Permite revisar lo que tienes:
- Cualquier instancia determinada de un
CommentId
determina funcionalmente laPerson
(FD:CommentId
->Person
) - Cualquier instancia determinada de un
CommentId
determina funcionalmente elComment
(FD:CommentId
->Comment
) - Cualquier instancia determinada de un
CommentId
determina funcionalmenteUserId
(FD:CommentId
->UserId
) - Cualquier instancia determinada de un
CommentId
determina funcionalmente elScore
(FD:CommentId
->Score
)
Todo aquí es un atributo dependiente solo en CommentId
y CommentId
. Esto podría llevarlo a la creencia de que una relación (tabla) que contiene todo, o un subconjunto de, los atributos anteriores debe ser normalizada.
Lo primero que debe preguntarse es ¿por qué creó el atributo CommentId
todos modos? Estrictamente hablando, este es un atributo manufacturado, no se relaciona con nada ''real''. CommentId se conoce comúnmente como clave sustituta. Una clave sustituta es solo un valor inventado que representa un conjunto único de valores correspondiente a otro grupo de atributos. Entonces, ¿para qué grupo de atributos es un sustituto CommentId
? Podemos resolverlo haciendo las siguientes preguntas y agregando nuevas FD al modelo:
- 1) ¿Tiene un comentario que ser único? Si es así, el FD:
Comment
->CommentId
debe ser verdadero. - 2) ¿Se puede hacer el mismo comentario varias veces siempre que se trate de una persona diferente? Si es así, entonces FD:
Person
+Comment
->CommentId
debe ser verdadero y el FD en 1 de arriba es falso. - 3) ¿Se puede hacer el mismo comentario varias veces sobre la misma persona siempre que haya sido hecha por diferentes UserId''s? Si es así, los FD en 1 y 2 no pueden ser verdaderos, pero FD:
Person
+Comment
+UserId
->CommentId
puede ser verdadero. - 4) ¿Se puede hacer el mismo comentario varias veces sobre la misma persona por el mismo ID de usuario pero con diferentes puntajes? Esto implica FD:
Person
+Comment
+UserId
''+Score
->CommentId
es verdadero y los otros son falsos.
Exactamente uno de los anteriores 4 FD anteriores debe ser cierto. Cualquiera que sea, afecta cómo se normaliza su modelo de datos.
Supongamos que FD: Person
+ Comment
+ UserId
-> CommentId
resulta ser verdadero. Las consecuencias lógicas son que:
-
Person
+Comment
+UserId
yCommentId
sirven como claves equivalentes con respecto aScore
-
Score
debería ponerse en relación con una, pero no con ambas, de sus claves (para evitar dependencias transitivas). La opción obvia seríaCommentId
ya que fue creado específicamente como un sustituto. - Se necesita una relación compuesta por:
CommentId
,Person
,Comment
,UserId
para vincular la clave a su sustituto.
Desde un punto de vista teórico, la clave sustituta CommentId
no es necesaria para que su modelo de datos o base de datos funcione. Sin embargo, su presencia puede afectar cómo se construyen las relaciones.
La creación de claves sustitutivas es un tema práctico de cierta importancia. Considere lo que podría pasar si elige no usar una clave sustituta, pero el atributo completo establece Person
+ Comment
+ UserId
en su lugar, especialmente si se lo requería en varias tablas como una clave externa o principal:
- Los comentarios pueden agregar una gran cantidad de espacio sobrecarga a su base de datos porque se repite en varias tablas. Probablemente es más que un par de caracteres de largo.
- ¿Qué sucede si alguien elige editar un comentario? Ese cambio debe propagarse a todas las tablas donde Comment es parte de una clave. No es una bonita vista!
- La indexación de claves complejas largas puede ocupar mucho espacio y / o generar un rendimiento de actualización lento
El valor asignado a una clave sustituta nunca cambia, sin importar lo que haga con los valores asociados a los atributos que determina. La actualización de los atributos dependientes ahora está limitada a la única tabla que define la clave sustituta. Esto es de gran importancia práctica.
Ahora volvemos a si deberías estar creando un sustituto para Person
. ¿Vive la Person
en el lado izquierdo de muchos FD o de alguno? Si lo hace, su valor se propagará a través de su base de datos y existe la posibilidad de crear un sustituto para él. Si la persona es un atributo numérico o de texto es irrelevante para la opción de crear una clave sustituta.
De acuerdo con lo que ha dicho, hay en el mejor de los casos un argumento débil para crear un sustituto para Person
. Este argumento se basa en la sospecha de que su valor puede convertirse en algún momento en una clave o parte de una clave en algún momento en el futuro.
Si nunca tiene la intención de asociar la columna de persona con un usuario o cualquier otra cosa y aparentemente los datos no necesitan constancia ni comprobaciones de integridad de datos, ¿por qué está esto en una base de datos relacional? ¿No sería este un caso de uso para una base de datos nosql? ¿O me estoy perdiendo algo?
Si ya ha alcanzado todas sus capacidades y no tiene planes de ampliar las capacidades, creo que lo deja como está.
Si planea agregar más, es decir, permitir que las personas tengan cuentas, o cualquier cosa en realidad, creo que sería inteligente separar sus datos en tablas Persona, Comentarios. No es difícil y facilita la expansión de su funcionalidad.
Tienes razón.
Person
puede ser una cosa en general, pero no en su modelo. Si fueras a molestar a las personas para que identifiquen correctamente a la persona de la que están hablando, sería necesaria una tabla de Person
. Por ejemplo, si los comentarios fueron solo sobre personas ya registradas en la base de datos.
Pero aquí parece que tienes datos no estructurados, sin identidad; y que nada / nadie está interesado en asegurarse de si "jenny" y "jennyyy" son de hecho la misma persona, sin mencionar "jenny doe", y "mi primo" ...
Yo votaría por tu amigo. Me gusta normalizar y planificar para el futuro e incluso si nunca lo necesita, esta normalización es tan fácil de hacer que, literalmente, no lleva tiempo. Puede crear una vista que consulte para hacer su SQL más limpio y eliminar la necesidad de que usted se una a las tablas usted mismo.
En mi opinión, tu amigo tiene razón.
La persona debe vivir en una mesa diferente y debe intentar normalizarse. No exageres, sin embargo.
A la larga, es posible que desee hacer más cosas con su sitio, por ejemplo, si desea adjuntar varios archivos a una persona (es decir, imágenes), le agradeceré mucho la normalización.
Siempre que trabaje con usuarios, debe haber una mesa dedicada. Luego puede unir las tablas y referirse a la ID de ese usuario.
user -> id | username | password | email
comment -> id | user_id | content
SQL para unir los comentarios a los usuarios:
SELECT user.username, comment.content FROM user JOIN comment WHERE user.id = comment.user_id;
Lo hará mucho más fácil en el futuro cuando desee buscar información sobre ese usuario específico. La cantidad de esfuerzo extra es insignificante.
Con respecto al "puntaje" para cada comentario, también debería ser una tabla separada. De esta forma, puede conectar a un usuario a "me gusta" o "no me gusta".
Con esta base de datos, puede sentir que está bien, pero puede haber algún problema en el futuro cuando desee que los usuarios sepan más de la base de datos. Supongamos que desea saber sobre la cantidad de comentarios hechos sobre una persona con el nombre = ''abc''. En este caso, tendrá que pasar por la tabla completa de comentarios y seguir contando. En lugar de esto, puede tener un atributo llamado ''conteo'' para cada persona e incrementarlo siempre que se haga un comentario en ese persona.
En lo que respecta a la normalización, siempre es mejor tener una base de datos normalizada porque reduce la redundancia y hace que la base de datos sea intuitiva. Si espera que su base de datos crezca en el futuro, entonces la normalización debe estar presente.