Pergunta

Eu tenho alguns produtos que pertence à alguma categoria.

Cada categoria pode ter propriedades diferentes.

Por exemplo,

  • Categoria carros tem propriedades cor , poder, ...
  • categoria animais de estimação tem propriedades peso , idade , ...

Número de categorias é de cerca de 10-15. Número de propriedades em cada categoria é 3-15. Número de produtos é muito grande.

A principal exigência para este aplicativo é muito boa pesquisa. Vamos selecionar a categoria e inserir critérios para cada propriedade nesta categoria.

tem que projetar banco de dados para este cenário. (SQL Server 2005)

Foi útil?

Solução

A abordagem de design clássico seria (a estrela denota a coluna de chave primária):

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

Se você pode viver com o fato de que cada valor da propriedade iria para o DB como uma informação de corda e conversão de tipo é armazenado na tabela de propriedade, esta disposição seria suficiente.

A consulta seria algo como isto:

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

O mais condições WHERE você fornecer (conjunctively, por exemplo, usando AND), mais rápida a consulta será. Se você tiver indexado adequadamente suas tabelas, é isso.

Como é, a solução não é ideal para uma situação de indexação de texto completo. Uma tabela adicional que armazena todo o texto associado a um ProductId de uma forma mais denormalized poderia ajudar aqui. Esta tabela seria necessário atualizar através de gatilhos que escutar alterações na tabela de ProductProperty.

Outras dicas

Se o usuário do aplicativo tem para selecionar uma categoria antes que eles possam procurar, eu iria separar seus produtos em diferentes tabelas de banco de dados por categoria. Esta solução também é indicada pelo fato de que os próprios categorias têm muito pouco em comum. Dividi-lo por categoria também vai fazer cada pesquisa muito mais rápido, pois o tempo não será desperdiçado procurando por carros quando seu usuário está procurando um animal de estimação.

Uma vez que você tem os produtos divididos em categorias, que deve ser fácil para criar as tabelas usando as propriedades comuns dos produtos em cada categoria. A interface do usuário do seu aplicativo deve ser dinâmico (Estou pensando em um formulário web), em que as propriedades que o usuário pode escolher deve mudar quando o usuário seleciona uma categoria.

Por favor note que se você tem produtos que deseja listados em várias categorias, esta solução irá resultar em dados duplicados em suas tabelas. Há um trade-off entre velocidade e normalização ao projetar um banco de dados. Se você não tem produtos que se encaixam em várias categorias, então eu penso que esta será a solução mais rápida (em termos de velocidade de pesquisa).

A maioria das pessoas estão aconselhando a usar variações do projeto do atributo de entidade Valor (EAV). Este projeto é um exagero para a sua situação, e introduz um monte de problemas, por exemplo:

  • Você não pode definir o tipo de dados para um atributo; você pode digitar "banana" para um atributo inteiro
  • Você não pode declarar um atributo como obrigatório (ou seja NOT NULL em uma mesa convencional)
  • Você não pode declarar uma restrição de chave estrangeira em um atributo

Se você tem um pequeno número de categorias, é melhor usar a solução A na resposta de Bogdan Maxim. Ou seja, definir uma tabela Produtos com atributos comuns a todas as categorias, e uma tabela adicional para cada categoria, para armazenar os atributos específicos da categoria.

Só se você tem um número infinito de categorias ou se você deve potencialmente suportar um conjunto diferente de atributos por linha em produtos é EAV uma boa solução. Mas então você não está usando um banco de dados relacional em tudo, desde EAV viola várias regras de normalização.

Se você realmente precisa que muita flexibilidade, você seria melhor fora de armazenar seus dados em XML. Na verdade, você pode olhar para RDF e frameworks web semânticas como Sesame .

Você pode querer considerar um Entidade-Atributo-Valor tipo de arranjo, onde você pode "marcar" cada produto com pares nome arbitrário / valor de atributos.

Você pode tentar isso. Eu não estou muito certo dos detalhes reais de sua pergunta, talvez alguém possa ajudar a traduzir um pouco melhor.

5 mesas. 3 para o armazenamento de dados, dois para armazenar os mapeamentos entre dados.

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

As consultas terão de juntar-se os dados utilizando as tabelas de mapeamento, mas isso vai permitir que você tenha diferentes muitos para muitos relacionamentos entre a categoria, propriedades e produtos.

Use procedimentos ou consultas parametrizadas armazenado para obter um melhor desempenho das suas pesquisas.

Se você quiser ser flexível em suas categorias e propriedades, você deve criar tabelas seguintes:

  • produto: ProductID
  • categoria: CategoryID, ProductID
  • propriedade: Imóvel, CódigoDaCategoria

quando você quiser compartilhar uma categoria mais mroe de um produto, você tem que criar uma tabela de ligação para o n: m juntar-se:

  • productCategoryPointer:. ProdCatID, ProductID, CódigoDaCategoria

Você terá que para alguns se junta em suas consultas, mas com os índices certos, você shoulb ser capaz de consultar seus dados rapidamente.

Você poderia tentar orientada algo mais objeto.

1. Definir uma tabela base para os produtos

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

2. Definir uma tabela Categorias

Categories(CategoryID, Name, Description, ..)

A partir daqui você tem um monte de opções e quase todos eles vão quebrar a normalização do seu banco de dados.

Solução A.

Será um pesadelo maintaince se você precisa adicionar novos produtos

A1. Definir uma tabela separada para cada uma das categorias

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

A2. Associar as tabelas com base nas relações, a fim de utilizar os dados

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

Solução B.

Maintainance pesadelo para diferentes tipos de propriedades (isto é int, VARCHAR, etc)

B1. Definir uma tabela de Propriedades

CategoryProperty (CPID, Name, Type)

B2. Definir uma tabela para manter as associações entre as categorias e as propriedades

PropertyAssociation (CPID, PropertyID)

B12. Definir uma tabela para manter as propriedades (Alternativa para B1 e B2)

Properties(CategoryID, PropertyID, Name, Type)

B3. Para cada tipo de propriedade (int, double, varchar, etc.) adicionar uma tabela de valores

PropertyValueInt(ProductID, CPID, PropertyID, Value) - para int PropertyValueString(ProductID, CPID, PropertyID, Value) - para cordas PropertyValueMoney(ProductID, CPID, PropertyID, Value) - por dinheiro

B4. Junte-se a todas as tabelas para recuperar a propriedade desejada.

Usando essa abordagem, você não tem que gerenciar todas as propriedades na tabela separada, mas os tipos de valor deles. Basicamente todas as tabelas envolvidas será lookup tabelas. A desvantagem, é que, a fim de recuperá cada valor, você tem que "Case" para cada tipo de valor.

Leve em mente estes artigos ( aqui e aqui ) ao escolher qualquer uma destas abordagens. Este post no fórum Também é interessante e de alguma forma relacionados com o tema, mesmo embora seja sobre a localização.

Você também pode usar ea resposta de Tomalak adicionar tipagem forte, se você sente a necessidade.

Recentemente, tive de fazer isso e eu estou usando NHibernate onde eu tenho três entidades

Categoria do produto Opção OptionCategory

Um produto tem 1 * Categorias

Um produto tem 1 * Opção

Uma opção tem 1 OptionCategory

Uma vez que este está configurado você pode usar Nhibernate cache

Felicidades

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top