Pregunta

Tengo algunos productos que pertenecen a alguna categoría.

Cada categoría puede tener diferentes propiedades.

Por ejemplo,

  • categoría automóviles tiene propiedades color , poder, ...
  • Las
  • categorías mascotas tienen propiedades peso , edad , ...

El número de categorías es de aproximadamente 10-15. El número de propiedades en cada categoría es 3-15. La cantidad de productos es muy grande.

El requisito principal para esta aplicación es una muy buena búsqueda. Seleccionaremos la categoría e ingresaremos los criterios para cada propiedad en esta categoría.

Tiene que diseñar una base de datos para este escenario. (SQL Server 2005)

¿Fue útil?

Solución

El enfoque de diseño clásico sería (la estrella denota la columna de clave principal):

Product
  ProductId*
  CategoryId: FK to Category.CategroyId
  Name

Category
  CategoryId*
  Name

Property
  PropertyId*
  Name
  Type

CategoryProperty
  CategoryId*: FK to Category.CategoryId
  PropertyId*: FK to Property.PropertyId

ProductProperty
  ProductId*: FK to Product.ProductId
  PropertyId*: FK to Property.PropertyId
  ValueAsString

Si puede vivir con el hecho de que cada valor de propiedad iría a la base de datos como una cadena y la información de conversión de tipo se almacena en la tabla de Propiedades, este diseño sería suficiente.

La consulta sería algo como esto:

SELECT
   Product.ProductId,
   Product.Name AS ProductName,
   Category.CategoryId,
   Category.Name AS CategoryName,
   Property.PropertyId,
   Property.Name AS PropertyName,
   Property.Type AS PropertyType,
   ProductProperty.ValueAsString
FROM
   Product 
   INNER JOIN Category         ON Category.CategoryId = Product.CategoryId
   INENR JOIN CategoryProperty ON CategoryProperty.CategoryId = Category.CategoryId
   INNER JOIN Property         ON Property.PropertyId = CategoryProperty.PropertyId
   INNER JOIN ProductProperty  ON ProductProperty.PropertyId = Property.PropertyId
                                  AND ProductProperty.ProductId = Product.ProductId
WHERE
   Product.ProductId = 1

Cuantas más condiciones WHERE proporcione (de forma conjunta, por ejemplo, usando AND), más rápida será la consulta. Si ha indexado correctamente sus tablas, eso es.

Tal como está, la solución no es ideal para una situación de indexación de texto completo. Aquí podría ayudar una tabla adicional que almacene todo el texto asociado con un ProductId de una manera más desnormalizada. Esta tabla necesitaría actualizarse a través de activadores que escuchen los cambios en la tabla ProductProperty.

Otros consejos

Si el usuario de la aplicación tiene para seleccionar una categoría antes de que pueda buscar, separaría sus productos en diferentes tablas de base de datos por categoría. Esta solución también está indicada por el hecho de que las categorías mismas tienen muy poco en común. Desglosarlo por categoría también hará que cada búsqueda sea mucho más rápida, ya que no se perderá tiempo buscando en los automóviles cuando su usuario esté buscando una mascota.

Una vez que haya dividido los productos en categorías, debería ser fácil crear las tablas utilizando las propiedades comunes de los productos en cada categoría. La interfaz de usuario de su aplicación debe ser dinámica (estoy pensando en un formulario web), ya que las propiedades que el usuario puede elegir deben cambiar cuando el usuario selecciona una categoría.

Tenga en cuenta que si tiene productos que desea enumerar en varias categorías, esta solución generará datos duplicados en sus tablas. Existe un compromiso entre velocidad y normalización al diseñar una base de datos. Si no tiene productos que se ajusten a múltiples categorías, entonces creo que esta será la solución más rápida (en términos de velocidad de búsqueda).

La mayoría de las personas recomiendan utilizar variaciones del diseño Entity-Attribute-Value (EAV). Este diseño es excesivo para su situación e introduce muchos problemas, por ejemplo:

  • No puede definir el tipo de datos para un atributo; puede ingresar " banana " para un atributo entero
  • No puede declarar un atributo como obligatorio (es decir, NO NULO en una tabla convencional)
  • No puede declarar una restricción de clave externa en un atributo

Si tiene un pequeño número de categorías, es mejor usar la solución A en la respuesta de Bogdan Maxim. Es decir, defina una tabla Productos con atributos comunes a todas las categorías, y una tabla adicional para cada categoría, para almacenar los atributos específicos de la categoría.

Solo EAV es una buena solución si tiene un número infinito de categorías o si potencialmente debe admitir un conjunto diferente de atributos por fila en Productos. Pero entonces no está utilizando una base de datos relacional, ya que EAV viola varias reglas de normalización.

Si realmente necesita tanta flexibilidad, sería mejor almacenar sus datos en XML. De hecho, puede consultar RDF y marcos web semánticos como Sesame .

Es posible que desee considerar un tipo de Entity-Attribute-Value arreglo, donde puede " etiquetar " cada producto con pares de atributos de nombre / valor arbitrarios.

Puedes probar esto. No estoy muy seguro de los detalles reales de su pregunta, tal vez alguien pueda ayudarlo a traducir un poco mejor.

5 mesas. 3 para almacenar los datos, 2 para almacenar las asignaciones entre datos.

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

Sus consultas necesitarán unir los datos usando las tablas de mapeo, pero esto le permitirá tener diferentes relaciones entre categorías, propiedades y productos.

Use procedimientos almacenados o consultas parametrizadas para obtener un mejor rendimiento de sus búsquedas.

Si desea ser flexible en sus categorías y propiedades, debe crear las siguientes tablas:

  • producto: ProductID
  • categoría: Id. de categoría, Id. de producto
  • propiedad: PropertyID, CategoryID

cuando desea compartir una categoría sobre más de un producto, debe crear una tabla de enlaces para la unión n: m:

  • productCategoryPointer: ProdCatID, ProductID, CategoryID.

Tendrá que unirse a algunas de sus consultas, pero con los índices correctos, podrá consultar sus datos rápidamente.

Podría intentar algo más orientado a objetos.

1. Definir una tabla base para productos

Products(ProductID, CategoryID, <any other common properties>)

2. Definir una tabla Categorías

Categories(CategoryID, Name, Description, ..)

Desde aquí tienes muchas opciones y casi todas romperán la normalización de tu base de datos.

Solución A.

Será una pesadilla de mantenimiento si necesita agregar nuevos productos

A1. Defina una tabla separada para cada una de las categorías

Cars(CarID, ProductID, ..) Pets(PetID, ProductID, ..)

A2. Unir las tablas según las relaciones para utilizar los datos

SELECT <fields> FROM Cars INNER JOIN Products ON Cars.ProductID = Products.ProductID

Solución B.

Pesadilla de mantenimiento para diferentes tipos de propiedades (es decir, int, varchar, etc.)

B1. Definir una tabla para Propiedades

CategoryProperty (CPID, Name, Type)

B2. Defina una tabla para contener las asociaciones entre Categorías y Propiedades

PropertyAssociation (CPID, PropertyID)

B12. Defina una tabla para contener las propiedades (Alternativa para B1 y B2)

Properties(CategoryID, PropertyID, Name, Type)

B3. Para cada tipo de propiedad (int, double, varchar, etc.) agregue una tabla de valores

PropertyValueInt(ProductID, CPID, PropertyID, Value) - para int PropertyValueString(ProductID, CPID, PropertyID, Value) - para cadenas PropertyValueMoney(ProductID, CPID, PropertyID, Value) - por dinero

B4. Une todas las tablas para recuperar la propiedad deseada.

Al usar este enfoque, no tendrá que administrar todas las propiedades en una tabla separada, sino los tipos de valor de ellas. Básicamente todas las tablas involucradas serán tablas de búsqueda. La desventaja es que, para recuperar cada valor, debe & "; Caso &"; para cada tipo de valor.

Tenga en cuenta estos artículos ( aquí y aquí ) al elegir cualquiera de estos enfoques. Esta publicación del foro también es interesante y de alguna manera relacionada con el tema, incluso aunque se trata de localización.

También puede usar La respuesta de Tomalak y agrega una escritura fuerte si sientes la necesidad.

Recientemente tuve que hacer esto y estoy usando NHibernate donde tengo tres entidades

Opción de categoría de producto OptionCategory

Un producto tiene 1 * Categorías

Un producto tiene 1 * Opción

Una opción tiene 1 OptionCategory

una vez configurado, puede utilizar el almacenamiento en caché de Nhibernate

Saludos

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top