Me estoy acercando a un proyecto donde tendré que implementar una base de datos con mi jefe; Somos una empresa muy pequeña, por lo que el ambiente de trabajo es muy personal.
Me había dado una de las bases de datos de la compañía antes y estaba completamente en contra de lo que me enseñaron (y leí sobre) en la escuela para RDBMS. Por ejemplo, aquí hay bases de datos completas que consisten en una tabla (por base de datos independiente). Una de esas tablas tiene más de 20 columnas de largo y para el contexto, estos son algunos de los nombres de columna de una tabla:
lngStoreID | vrStoreName | lngCompanyID | vrCompanyName | lngProductID | vrProductName
El punto es que donde debería tener tablas individuales que contengan los datos de la entidad (nombre, tamaño, fecha de compra, etc.) lo coloca todo en una tabla grande por base de datos.
Quiero mejorar este diseño, pero no estoy seguro de por qué un modelo de datos correctamente normalizado y segmentado realmente mejoraría este producto. Si bien estoy familiarizado con el diseño de bases de datos de la universidad y entiendo cómo hacerlo, no estoy seguro de por qué esto realmente mejora las bases de datos.
¿Por qué un buen esquema relacional mejora una base de datos?
fuente
He [the boss] had given me one of his databases before and it completely went against what I was taught (and read about) in school for RDBMS
<- ¡Bienvenido al mundo real!Respuestas:
El argumento del rendimiento suele ser el más intuitivo. Especialmente desea señalar cómo será difícil agregar buenos índices en una base de datos normalizada incorrectamente (nota: hay casos extremos en los que la desnormalización puede de hecho mejorar el rendimiento, pero cuando ambos no tienen experiencia con bases de datos relacionales, es probable que no sea fácil ver estos casos).
Otro es el argumento del tamaño de almacenamiento. Una tabla desnormalizada con muchas redundancias requerirá mucho más almacenamiento. Esto también influye en el aspecto del rendimiento: cuantos más datos tenga, más lentas serán sus consultas.
También hay un argumento que es un poco más difícil de entender, pero de hecho es más importante porque no puedes resolverlo arrojándole más hardware. Ese es el problema de consistencia de datos. Una base de datos correctamente normalizada se encargará de que un producto con una ID específica siempre tenga el mismo nombre. Pero en una base de datos desnormalizada, tales inconsistencias son posibles, por lo que se debe tener especial cuidado cuando se trata de evitar inconsistencias, lo que tomará tiempo de programación para hacerlo bien y aún causará errores que le costarán la satisfacción del cliente.
fuente
El uso del software dedicado de gestión de bases de datos podría ser considerablemente más fácil (lo siento, no pude resistir).
Si esta base de datos solo se preocupa por "registrar" qué producto se vendió, dónde, cuándo y por quién, entonces podría extender la definición de "base de datos OK" lo suficiente como para cubrirla. Si estos datos se están utilizando para algo más, entonces es realmente bastante pobre.
Pero ...
¿La aplicación / consultas que utilizan estos datos responden mal / lentamente? Si no, entonces no hay un problema real para resolver. Claro, se ve y se siente feo, pero si funciona, entonces no obtendrá ningún "punto" por sugerir que "podría" ser mejor.
Si puede encontrar síntomas definitivos (es decir, problemas) que parecen ser causados por un modelado de datos deficiente, prototipo de una solución mejor. Tome una copia de una de estas "bases de datos", normalice los datos y vea si su solución funciona mejor. Si es considerablemente mejor (y esperaría que cualquier operación de actualización de estos datos se mejorara enormemente ), vuelva a su jefe y muéstrele la mejora.
Es perfectamente posible recrear su "vista de tabla única" de los datos con ... bueno ... Vistas.
fuente
La respuesta es: no siempre mejora una base de datos. Debes saber que lo que probablemente te enseñaron se llama Tercera forma normal .
Otros formularios son válidos en algunas situaciones, lo cual es clave para responder a su pregunta. Su ejemplo se parece a la primera forma normal , si eso lo ayuda a sentirse mejor sobre su estado actual.
Las reglas 3NF establecen relaciones entre los datos que "mejoran" una base de datos:
Evite que los datos no válidos ingresen a su sistema (si una relación es 1 a 1, fuerza un error a pesar del código escrito encima). Si sus datos son consistentes en la base de datos, es menos probable que den lugar a inconsistencias fuera de su base de datos.
Proporciona una forma de validar el código (por ejemplo, una relación de muchos a uno es una señal para restringir las propiedades / comportamientos de un objeto). Al escribir código para usar la base de datos, a veces los programadores notan la estructura de datos como un indicador de cómo debería funcionar su código. O pueden proporcionar comentarios útiles si la base de datos no coincide con su código. (Esto es más como una ilusión, desafortunadamente).
Proporcione reglas que puedan ayudarlo significativamente a reducir los errores al crear una base de datos, de modo que no lo haga basándose en requisitos arbitrarios que pueden surgir en cualquier momento durante la vida de una base de datos. En cambio, está evaluando sistemáticamente la información para lograr objetivos específicos.
Las estructuras adecuadas de la base de datos conducen a un mejor rendimiento al conectar los datos de manera que minimizan el almacenamiento de datos, minimizan las llamadas de almacenamiento para recuperar datos, maximizan los recursos en memoria y / o minimizan la clasificación / manipulación de datos para el conjunto de datos particular que tiene, en comparación con la consulta que está haciendo ejecutando en contra de ella. Pero la estructura "adecuada" depende de la cantidad de datos, la naturaleza de los datos, el tipo de consulta, los recursos del sistema, etc. Al normalizar puede empeorar el rendimiento (es decir, si carga todos los datos como 1 tabla, la unión puede ralentizarse una consulta). El procesamiento de transacciones (OLTP) frente a la inteligencia empresarial (almacén de datos) son muy diferentes.
En una pequeña empresa con pequeños conjuntos de datos, es posible que no haya nada de malo en la forma en que está ahora. Excepto que, si creces, será difícil "arreglar" más tarde, porque a medida que la tabla se agrande, los sistemas que la usan probablemente irán más despacio.
Por lo general, querrá enfatizar las transacciones rápidas a medida que una empresa crece. Sin embargo, si pasa tiempo en este proyecto ahora en lugar de otras cosas que la empresa puede necesitar con más urgencia, es posible que nunca tenga ese problema porque su empresa nunca crece realmente. Ese es el "desafío de optimización previa": dónde pasar su valioso tiempo en este momento.
¡Buena suerte!
fuente
WHERE
cláusula. Por supuesto, estos aún pueden salir mal, pero es menos probable en una situación normalizada ya que solo tiene que hacer coincidir una fila a través de la clave primaria.Existen múltiples razones por las que usar una gran "tabla de Dios" es malo. Trataré de ilustrar los problemas con una base de datos de ejemplo inventada. Supongamos que está tratando de modelar eventos deportivos. Diremos que desea modelar juegos y los equipos que juegan en esos juegos. Un diseño con varias tablas podría verse así (esto es muy simplista a propósito, así que no te quedes atrapado en lugares donde podría aplicarse una mayor normalización):
y una base de datos de una sola tabla se vería así
Primero, veamos cómo hacer índices en esas tablas. Si necesitaba un índice en la ciudad de origen para un equipo, podría agregarlo a la
Teams
tabla o a laTeamsAndGames
tabla con bastante facilidad. Recuerde que siempre que cree un índice, debe almacenarse en el disco en algún lugar y actualizarse a medida que se agregan filas a la tabla. En el caso de laTeams
tabla, esto es bastante sencillo. Puse un nuevo equipo, la base de datos actualiza el índice. ¿Pero para quéTeamsAndGames
? Bueno, lo mismo se aplica desde elTeams
ejemplo. Agrego un equipo, el índice se actualiza. ¡Pero también sucede cuando agrego un juego! Aunque ese campo será nulo para un juego, el índice aún debe actualizarse y almacenarse en el disco para ese juego de todos modos. Para un índice, esto no suena tan mal. Pero cuando necesita muchos índices para las múltiples entidades agrupadas en esta tabla, desperdicia mucho espacio almacenando los índices y mucho tiempo de procesador actualizándolos para cosas donde no se aplican.En segundo lugar, la coherencia de los datos. En el caso de usar dos mesas separadas, puedo usar claves externas de la
Games
mesa a laTeams
mesa para definir qué equipos están jugando en un juego. Y suponiendo que las columnasHomeTeamId
yAwayTeamId
no sean anulables, la base de datos garantizará que cada juego que coloque tenga 2 equipos y que esos equipos existan en mi base de datos. Pero, ¿qué pasa con el escenario de una sola mesa? Bueno, dado que hay varias entidades en esta tabla, esas columnas deben ser anulables (puede hacer que no sean anulables y colocar datos basura allí, pero eso es solo una idea horrible). Si esas columnas son anulables, la base de datos ya no puede garantizar que cuando inserte un juego tenga dos equipos.Pero, ¿qué pasa si decides ir de todos modos? Configura las claves foráneas de modo que esos campos apunten a otra entidad en la misma tabla. Pero ahora la base de datos solo se asegurará de que esas entidades existan en la tabla, no de que sean del tipo correcto. Podrías configurar fácilmente
GameHomeTeamId
la ID de otro juego y la base de datos no se quejará en absoluto. Si lo intentara en el escenario de tablas múltiples, la base de datos arrojaría un ajuste.Puede intentar mitigar estos problemas diciendo "bueno, nos aseguraremos de que nunca lo hagamos en código". Si confía en su capacidad para escribir código libre de errores la primera vez y en su capacidad para tener en cuenta todas las combinaciones extrañas de cosas que un usuario podría intentar, siga adelante. Personalmente, no confío en mi capacidad para hacer ninguna de esas cosas, así que dejaré que la base de datos me brinde una red de seguridad adicional.
(Esto empeora aún más si su diseño es uno en el que copia todos los datos relevantes entre filas en lugar de usar claves externas. Cualquier falta de ortografía / otras inconsistencias de datos será difícil de resolver. ¿Cómo puede saber si "Jon" es un error ortográfico de "John "o si fue intencional (porque son dos personas separadas)?)
En tercer lugar, casi todas las columnas deben ser anulables o deben llenarse con datos copiados o basura. Un juego no necesita un
TeamName
oTeamHomeCity
. Entonces, o cada juego necesita algún tipo de marcador de posición o debe ser anulable. Y si es anulable, la base de datos tomará un juego sin problemasTeamName
. También tomará un equipo sin nombre, incluso si la lógica de su negocio dice que eso nunca debería suceder.Hay un puñado de otras razones por las que desearía tablas separadas (incluida la preservación de la cordura del desarrollador). Incluso hay algunas razones por las que una tabla más grande podría ser mejor (la desnormalización a veces mejora el rendimiento). Esos escenarios son pocos y distantes entre sí (y generalmente se manejan mejor cuando tiene métricas de rendimiento para mostrar que ese es realmente el problema, no un índice faltante u otra cosa).
Finalmente, desarrolle algo que sea fácil de mantener. El hecho de que "funcione" no significa que esté bien. Tratar de mantener tablas de dioses (como las clases de dioses) es una pesadilla. Simplemente te estás preparando para el dolor más tarde.
fuente
Cita del día: " Teoría y práctica deberían ser lo mismo ... en teoría "
Mesa desnormalizada
Su tabla única de retención de datos contiene datos redundantes tiene una ventaja: hace que los informes en sus líneas sean muy simples de codificar y rápidos de ejecutar porque no tiene que hacer ninguna unión. Pero esto a un alto costo:
IngCompanyID
yvrCompanyName
). La actualización de datos maestros puede requerir la actualización de muchas más líneas que en un esquema normalizado.Tabla normalizada
Las desventajas anteriores son ventajas para el esquema normalizado. Por supuesto, las consultas pueden ser un poco más complejas de escribir.
En resumen, el esquema normalizado expresa mucho mejor la estructura y las relaciones entre sus datos. Seré provocativo y diré que es el mismo tipo de diferencia que entre la disciplina requerida para usar un conjunto de cajones de oficina ordenados y la facilidad de uso de un contenedor de basura.
fuente
Creo que hay al menos dos partes en su pregunta:
1. ¿Por qué no deberían almacenarse entidades de diferentes tipos en la misma tabla?
Las respuestas más importantes aquí son la legibilidad del código y la velocidad. A
SELECT name FROM companies WHERE id = ?
es mucho más legible que aSELECT companyName FROM masterTable WHERE companyId = ?
y es menos probable que haga preguntas sin sentido (por ejemploSELECT companyName FROM masterTable WHERE employeeId = ?
, no sería posible cuando las empresas y los empleados se almacenan en tablas diferentes). En cuanto a la velocidad, los datos de una tabla de base de datos se recuperan leyendo la tabla completa secuencialmente o leyendo un índice. Ambos son más rápidos si la tabla / índice contiene menos datos, y ese es el caso si los datos se almacenan en tablas diferentes (y solo necesita leer una de las tablas / índices).2. ¿Por qué las entidades de un solo tipo se dividen en subentidades que se almacenan en tablas diferentes?
Aquí, la razón es principalmente para evitar inconsistencias de datos. Con el enfoque de tabla única, para un sistema de gestión de pedidos, puede almacenar el nombre del cliente, la dirección del cliente y el ID del producto que el cliente solicitó como una entidad única. Si un cliente solicita varios productos, tendrá múltiples instancias del nombre y la dirección del cliente en su base de datos. En el mejor de los casos, acaba de obtener datos duplicados en su base de datos, lo que puede ralentizarlo un poco. Pero un caso peor es que alguien (o algún código) cometió un error cuando se ingresaron los datos para que una compañía termine con diferentes direcciones en su base de datos. Esto solo es bastante malo. Pero si tuviera que consultar la dirección de una empresa en función de su nombre (p. Ej.
SELECT companyAddress FROM orders WHERE companyName = ? LIMIT 1
) solo obtendría arbitrariamente una de las dos direcciones devueltas y ni siquiera se daría cuenta de que había una inconsistencia. Pero cada vez que ejecuta la consulta, en realidad puede obtener una dirección diferente, dependiendo de cómo DBMS resuelva internamente su consulta. Esto probablemente romperá su aplicación en otro lugar, y la causa raíz de esa ruptura será muy difícil de encontrar.Con el enfoque de varias tablas, se daría cuenta de que existe una dependencia funcional del nombre de la empresa a la dirección de la empresa (si una empresa solo puede tener una dirección), almacenaría la tupla (companyName, companyAddress) en una tabla (p. Ej.
company
) y la tupla (productId, companyName) en otra tabla (porder
. ej .). UnaUNIQUE
restricción en lacompany
tabla podría obligar a que cada compañía solo tenga una única dirección en su base de datos para que nunca surjan inconsistencias en las direcciones de la compañía.Nota: en la práctica, por razones de rendimiento, probablemente generaría un ID de compañía único para cada compañía y lo usaría como una clave externa en lugar de usar directamente el nombre de la compañía. Pero el enfoque general sigue siendo el mismo.
fuente
TL; DR : están diseñando la base de datos en función de cómo se les enseñó cuando estaban en la escuela.
Podría haber escrito esta pregunta hace 10 años. Me llevó algo de tiempo entender por qué mis predecesores diseñaron sus bases de datos de la manera en que lo hicieron. Estás trabajando con alguien que:
No sospecho que sea el número 1, ya que en realidad tiene números de identificación en su tabla, por lo que asumiré el número 2.
Después de salir de la escuela, estaba trabajando para una tienda que usaba un AS / 400 (también conocido como IBM i). Encontré algunas cosas extrañas en la forma en que diseñaron sus bases de datos, y comencé a recomendar que hagamos cambios para seguir cómo me enseñaron a diseñar bases de datos. (Yo era tonto en ese entonces)
Se necesitó un paciente programador mayor para explicarme por qué las cosas se hicieron de esa manera. No habían cambiado el esquema porque habría provocado la ruptura de programas que eran más antiguos que yo. Literalmente, el código fuente de un programa tenía una fecha de creación del año anterior a mi nacimiento. En el sistema en el que estábamos trabajando, sus programas tenían que implementar toda la lógica y las operaciones que el planificador de consultas de su base de datos maneja por usted. (Puede ver eso ejecutando EXPLAIN en una de sus consultas)
Estaba actualizado sobre las técnicas que estaba tratando de implementar, pero mantener el sistema en funcionamiento era más importante que hacer cambios "porque iba en contra de lo que me enseñaron". Cada nuevo proyecto que cualquiera de nosotros comenzó hizo un mejor uso del modelo relacional que pudimos. Desafortunadamente, otros programadores / consultores de esa época todavía diseñaron sus bases de datos como si estuvieran trabajando con las restricciones anteriores de ese sistema.
Algunos ejemplos de lo que encontré que no se ajustaban al modelo relacional:
code1,code2, ..., code20
. Ej. )Las razones que se me dieron para tomar esas decisiones de diseño se basaron en las restricciones del sistema cuando se diseñó la base de datos por primera vez.
Fechas : me dijeron que llevó más tiempo de procesamiento usar las funciones de fecha (qué mes, día o día de la semana) para procesar una fecha que para crear una tabla de cada fecha posible con toda esa información.
Columnas secuenciales del mismo tipo : el entorno de programación en el que se encontraban permitió que un programa creara una variable de matriz sobre parte de la fila. Y fue una forma más fácil de reducir el número de operaciones de lectura.
Columnas CHAR de longitud NxM : fue más fácil insertar los valores de configuración en una columna para reducir las operaciones de lectura de archivos.
Un ejemplo mal concebido en C equivalente para reflejar el entorno de programación que tenían:
Según lo que me dijeron, parte de esto se consideró la mejor práctica en ese momento.
fuente