tool software online lucidchart generate data database design database-design

software - database diagram tool



Una mesa o muchas? (15)

"la vida es más fácil con la única mesa grande": he visto la consecuencia natural de esto, ser una mesa con más de 100 columnas, y puedo decir que no me agrada trabajar con esta.

El problema principal es que los diseñadores de tales tablas tienden a omitir las restricciones requeridas para garantizar la integridad de los datos. Por ejemplo, el OP dice:

una referencia de diario requiere tanto un título de revista como un título de artículo, y también un número de página, mientras que un libro requiere un editor y una fecha de publicación que los artículos de revistas no requieren

... lo que implica las siguientes limitaciones:

CONSTRAINT a_journal_must_have_a_journal_title CHECK ( type <> ''journal'' OR journal_title IS NOT NULL ); CONSTRAINT a_journal_must_have_an_article_title CHECK ( type <> ''journal'' OR article_title IS NOT NULL ); CONSTRAINT a_journal_must_have_a_page_number CHECK ( type <> ''journal'' OR page_number IS NOT NULL ); CONSTRAINT a_journal_cannot_have_a_publisher CHECK ( type <> ''journal'' OR publisher IS NULL ); CONSTRAINT a_journal_cannot_have_a_publication_date CHECK ( type <> ''journal'' OR publication_date IS NULL ); CONSTRAINT a_book_cannot_have_a_journal_title CHECK ( type <> ''book'' OR journal_title IS NULL ); CONSTRAINT a_book_cannot_have_a_article_title CHECK ( type <> ''book'' OR article_title IS NULL ); CONSTRAINT a_book_cannot_have_a_page_number CHECK ( type <> ''book'' OR page_number IS NULL ); CONSTRAINT a_book_must_have_a_publisher CHECK ( type <> ''book'' OR publisher IS NOT NULL ); CONSTRAINT a_jbook_must_have_a_publication_date CHECK ( type <> ''book'' OR publication_date IS NOT NULL );

... ¡y sospecho que es solo la punta del iceberg!

Es mi esperanza que después de escribir varios cientos de restricciones, el diseñador pueda tener dudas sobre todas esas columnas con nulos :)

Estoy tratando de diseñar una aplicación para contener información académica de referencia. El problema es que cada tipo diferente de referencia (por ejemplo, artículos de revistas, libros, artículos de periódicos, etc.) requiere información diferente. Por ejemplo, una referencia de revista requiere tanto un título de revista como un título de artículo, y también un número de página, mientras que un libro requiere un editor y una fecha de publicación que los artículos de revista no requieren.

Por lo tanto, debería tener todas las referencias almacenadas en una tabla en mi base de datos y simplemente dejar campos en blanco cuando no se aplican, o debería tener varias tablas como BookReferences, JournalReferences, NewspaperReferences y poner las referencias apropiadas en cada una. El problema entonces sería que haría la búsqueda a través de todas las referencias algo más difícil, y también la edición tendría que hacerse más bien probablemente por separado.

(Por cierto, planeo usar Ruby on Rails para este proyecto, pero dudo que eso haga la diferencia a esta pregunta de diseño)

Actualizar:

¿Más puntos de vista sobre esto? Esperaba obtener una respuesta simple diciendo que un método en particular definitivamente se consideraba "el mejor", pero como siempre, las cosas no son tan simples como esto. La opción de herencia de tabla única parece bastante interesante, pero no hay mucha información sobre ella que pueda encontrar muy fácilmente: puedo publicar otra pregunta en este sitio sobre eso.

Estoy dividido entre la respuesta de Olvak y la respuesta de Corey . La respuesta de Corey da una buena razón por la cual Olvak''s no es el mejor, pero la respuesta de Olvak da buenas razones por las cuales Corey''s no es el mejor. Nunca me di cuenta de que esto podría ser tan difícil ...

Cualquier otro consejo muy apreciado!


¿Qué tal ambos? ¡Tómate tu torta y cómala también!

Hay otra opción en algún lugar entre la "una gran mesa" y la base de datos "totalmente normalizada" que realmente combina lo mejor de ambos mundos: puede usar algo llamado vistas materializadas , que son como vistas porque son igual de flexibles y usted consulta como muchas tablas según sea necesario, configurar todas las combinaciones, etc., pero también son como tablas en las que los resultados se almacenan en una tabla.

Lo bueno de esto es que una vez que configura esto y decide cuándo debe actualizarse (cada vez que cambia una de las tablas subyacentes, o tal vez solo una vez por noche) ya no tiene que preocuparse más. Puede consultar la vista materializada como si fuera una gran tabla (porque lo es), y el rendimiento será rápido (más rápido que usar la instrucción de selección que está detrás). Lo que es más importante, no tiene los dolores de cabeza de mantener la integridad de los datos. Eso es lo que el DB está ahí para manejar.

Si no tiene un DB que lo admita de la caja, puede seguir usando esta idea creando una tabla con los resultados de la vista como un trabajo por lotes cada noche.


Creo que debe anticiparse a cómo se verá el SQL para cada una de las soluciones. Si pasas por ese ejercicio, entonces encontrarás que poner todo en una tabla es el más fácil de codificar y probablemente te lleve a tener el mejor rendimiento. Es más fácil separar las cosas que quieres de una tabla, luego es juntar las cosas de varias tablas.

Digamos que mi-uno-gran-mesa se ve así:

1 id
2 tipo
3 campo-común-a-libro-y-diario
4 campos específicos para reservar
5 campo-específico-a-diario

Si solo estoy interesado en libros, puedo crear una vista, o simplemente sql, como esta:

create view book as select id, field_common-to-book-and-journal, field-specific-to-book from my-one-big-table where type = ''book''

Entonces, es fácil simular que los datos están en tablas separadas cuando quiero.

Pero, si comienzo poniendo los datos en tablas separadas, terminaré escribiendo SQL así:

select id, field-common-to-book-and-journal from books union select id, field-common-to-book-and-journal from journal-articles union .... etc, for each type

No sé sobre otras bases de datos, pero hacer uniones en SQL Server puede ser costoso y existen restricciones cuando se trabaja con tipos de datos como ntext.

Si sigues el consejo de olavk, tu SQL para combinar tipos en una consulta terminaría luciendo así:

select common.id, common.field-common-to-book-and-journal, book.field-specific-to-book journal.field-specific-to-journal from common-table common left outer join book-specific-table book on left outer join journal-specific-table journal on ... etc, for each type

He trabajado con sistemas que utilizan las tres formas y, con mucho, la vida es más fácil con una única gran mesa.



Hay otra opción: no una que respalde completamente, pero sigue siendo otra opción:

Usa tres tablas:

refs (id, title, refType) -- title of the reference, and what type of reference it is fieldDef (id, fieldName, refType, dataType) -- name of the field, which reference types it applies to, and -- what type of data is stored in these fields (ISDN number, date, etc) fields (refId, fieldId, value) -- where you actually add data to the references.

refType puede ser el tipo de referencia, y si lo convierte en un entero con valores aumentados por potencias de dos (1, 2, 4, 8 ...), entonces pueden agregarse para formar una máscara de bits en la tabla fieldDef.

Pros : muy simple y extensible. Si se le ocurre otro tipo de referencia, o un nuevo tipo de campo para un tipo de referencia existente, se puede agregar muy rápidamente. Los formularios se pueden generar automáticamente para cada tipo de referencia. Todos los datos se almacenan en un solo lugar, lo que significa que no es necesario realizar un seguimiento de varios esquemas (¿esquemas?) Para las operaciones CRUD .

Contras : esto es lo que hace The Daily WTF. Las declaraciones seleccionadas pueden volverse muy confusas y complicadas. La base de datos no puede realizar la verificación de tipo (por ejemplo, para fechas, etc.) y el campo genérico de "valor" no se optimizará para los datos almacenados en él.


Lo que terminé haciendo en el pasado es usar subcategorías: tener una sola tabla con todos los campos comunes dentro de ella, y luego varias tablas que pueden tener una relación de cero o uno con la tabla "núcleo".

El ejemplo a continuación es similar a algo que usamos "en la naturaleza"; básicamente construye una estructura de datos jerárquica, donde cada nodo puede ser una carpeta o documento:

CREATE TABLE Node ( Id int identity primary key, ParentId int null references Node.ParentId, Name varchar(50) not null, Description varchar(max) null ) CREATE TABLE Doc ( Id int primary key references Node.Id, FileExtension char(3) not null, MimeType varchar(50) not null, ContentLength bigint not null, FilePathOnDisk varchar(255) ) CREATE TABLE Folder ( Id int primary key references Node.Id, ReadOnly bit not null )

Por lo tanto, su sproc de GetFolder hará:

SELECT n.Id, n.ParentId, n.Name, n.Description, f.ReadOnly FROM Node n JOIN Folder f ON n.Id = f.Id WHERE f.Id = @Id

Esto se traduce muy bien en la herencia basada en la clase:

public class Folder : Node { public bool IsReadOnly { get; set; } ...etc }


Me gustaría tener una sola tabla para todas las referencias, pero tablas adicionales como BookReferences, etc. para metadatos no aplicables para todos los tipos de referencia.

Buscar y consultar no sería más difícil: después de todo, solo podría crear una vista que agregue toda la información como en la solución de tabla única, y luego consultar esa vista más.

Tener todo en una mesa con muchos nulos puede parecer la solución más simple, pero en realidad generará muchos problemas. Por ejemplo: con tablas separadas puede definir qué campos son necesarios para cada BookReference, pero si todo está en una tabla, cada campo debe ser nulo y, por lo tanto, opcional. También sería más fácil insertar datos no válidos, como una referencia de libro que también contiene erróneamente un nombre de diario no nulo.

Editar: Algunas personas parecen temer las uniones. No temas la unión! Si usa exactamente la misma combinación en varias consultas que de hecho serían tediosas, en ese caso la unión debería definirse en una vista , y las consultas deberían consultar esa vista. Las vistas son realmente la abstracción básica de las bases de datos relacionales, y debe usarlas por las mismas razones por las que utiliza funciones en el código: para evitar la repetición y para encapsular y crear abstracciones.

Editar: hay algunos comentarios sobre el rendimiento. Es muy difícil adivinar de antemano el rendimiento de los esquemas DB, porque a menudo no es intuitivo. Por ejemplo, una combinación entre varias tablas puede ser más rápida que una exploración de tabla completa de una sola tabla; todo depende del tipo de consulta, la naturaleza de los datos, los índices disponibles, etc. Además, en muchos sistemas de bases de datos puede usar características como vistas materializadas para optimizar el rendimiento para diferentes consultas sin comprometer el modelo lógico. La "desnormalización para el rendimiento" es principalmente culto a la carga en estos días en mi humilde opinión, a menos que seas Google o Flickr.


Mi consejo es comenzar por diseñar la base de datos correctamente, es decir, utilizar la normalización para garantizar que las tablas solo contengan datos sobre una cosa (libro, revista, etc.) y que los atributos se almacenen en la tabla correcta.

Si en el futuro crea problemas de rendimiento, puede desnormalizarlo en menos tablas, pero es poco probable que esto sea un problema a menos que tenga una gran base de datos.

Cree una tabla que contendrá los atributos comunes para todas las referencias.

Cree tablas separadas para contener los atributos que son específicos para cada tipo de referencia.

El otro problema es si tendrá muchas referencias a un solo trabajo, por ejemplo, cientos de referencias a un diario en particular. La normalización sugeriría que tiene una tabla que contiene las revistas (título, autor, revista), una tabla que contiene la información de referencia que es específica de las revistas (artículo, página) y otra que contiene datos que son comunes a todas las referencias (fecha de referencia, tipo de referencia).


Mucho de lo que sería mejor depende de cuántos campos diferentes y tamaños de campo, usted tiene una restricción en el tamaño total de la fila (esto se puede ignorar en cierta medida sabiendo que todos los campos nunca se completarán, pero una vez que llegue a donde las páginas son demasiado amplias, el almacenamiento en realidad en la base de datos termina dividiendo la información, lo que hace que la recuperación dure más. Por lo tanto, si la información es pequeña y (esto es importante) no es probable que cambie mucho (sería un evento raro que necesitase agregar nuevo tipo de información aún no considerada), entonces la tabla única es la mejor ruta. Si la tabla fuera demasiado amplia o si estuviera sujeta a muchos cambios posibles en el tipo de datos que deben almacenarse, entonces la tabla de discusión sería un mejor enfoque, aunque siempre será más difícil consultarlo correctamente. Si a menudo desea consultar múltiples tipos de referencias al mismo tiempo, la tabla grande es un enfoque más eficiente. Si solo necesita tomar uno a la vez , pierdes muy poco yo n términos de eficiencia al tener las uniones.

Si opta por seguir la ruta de una tabla, asegúrese de colocar desencadenantes en la tabla que apliquen las reglas de integridad de datos para cada tipo de datos. Lo necesitará porque no puede confiar en que los campos sean necesarios.

Un problema con tener las tablas separadas es que no sabe hasta el tiempo de ejecución a cuál de las tablas necesita unirse. Esto lo coloca en el ámbito del SQl dinámico del que no soy partidario (por razones de seguridad y eficiencia y mantenimiento) o le hace participar en tablas que puede o no necesitar, lo que es ineficiente.

Otra posibilidad es almacenar toda la cadena de referencia en un campo más grande y usar la interfaz de usuario para verificar que todas las partes necesarias estén allí antes de concatenar el registro y enviar la información a la base de datos. Esta sería la consulta más rápida para la mayoría de las consultas que desean toda la información, pero sería una molestia si necesita extraer solo algunos de los datos. También se basa en todos los datos que se insertan a través de la interfaz de usuario, que pueden o no ser el caso para usted. Honestamente, no puedo ver dónde necesitarías esta información desglosada por separado, así que este es el enfoque que probablemente tomaría. Pero no conozco las reglas de su negocio, así que tómenlo con un grano de sal.


No creo que la necesidad de unir mesas sea particularmente tediosa; Tomaría el enfoque más normal aquí.


Olavk hace buenos puntos, y Corey da una gran explicación detallada. La lectura de la información de Corey, sin embargo, me da una conclusión de la respuesta de Olavk. Tenga en cuenta que, dependiendo de lo que esté haciendo con la información, puede terminar 2 etapas de su consulta. Encuentre el artículo, luego, para cada referencia, haga una selección directa de lo que le interese.

También considere la idea de almacenar todo en múltiples tablas y leerlo desde una sola tabla. Lo hago para una gran base de datos que tengo, donde la mayoría de las consultas necesitan cierta información común, pero todavía se requiere el diseño completo de varias tablas. Las inserciones se ralentizan un poco por los desencadenantes que inician (en mi caso, uno por archivo donde cada archivo es responsable de hasta un millón de filas insertadas), pero mis últimas consultas de selección pueden ir de minutos a segundos de un solo dígito.

Almacenamiento de datos :)


Rails es compatible con la herencia Single-Table y los tipos Polymorphic ActiveRecord. Sugeriría investigar esto: ActiveRecord tiene algunas opiniones sobre cómo debería estructurarse la base de datos.


Tener una sola tabla con el campo "tipo" será problemático cuando se agrega un nuevo tipo de referencia que necesita campos adicionales. La extensión de los valores de campo de tipo no es un problema, pero tendría que agregar columnas a la tabla, completar los valores predeterminados para todas las filas actuales, etc.

Tener tablas separadas haría que agregar un nuevo tipo de referencia (¡y automáticamente generar un formulario para él!) Y la búsqueda no sería más difícil.


Tuve una discusión sobre estos temas hace algún tiempo con mi superior. Por supuesto, no pude probar que el "enfoque jerárquico de mesas múltiples " (vea la respuesta de olavk ) sea mejor, ¡pero lo sentí! Yo siempre elegiría este método. Una tabla raíz con todos los campos que las entidades tienen en común, y 1-1 tablas secundarias con campos que no tienen en común. Si es necesario, este enfoque puede extenderse a más tablas secundarias, siempre que la lógica de negocios y otras entidades tengan algo fuera de él. Es decir, no creo que haya que ir por la borda con esto.

También estoy en contra de crear tablas "secundarias" separadas sin la tabla raíz, donde cada tabla tiene una copia de los mismos campos. Creo que la respuesta de Corey sugiere tal enfoque como un ejemplo de un mal modelo de varias mesas, y también lo critica. Me gustaría agregar que tener que escribir uniones no es el problema principal con eso. No es un problema en absoluto, ya que la mayoría de las consultas de bases de datos tienen muchas combinaciones, y es algo normal. Es difícil crear relaciones con otras tablas: siempre necesita un ID y un TypeId para saber qué tabla está vinculada a él. En el caso de una tabla raíz, solo necesita el Id.


una mesa y un campo "tipo" serían mi sugerencia