Estou trabalhando para atualizar o banco de dados de produtos do nosso site. Ele é construído no MySQL, mas essa é mais uma questão geral de padrão de design de banco de dados.
Estou pensando em mudar para um padrão Supertype / Subtype. Nosso banco de dados atual / anterior é principalmente uma tabela única que possui dados sobre um único tipo de produto. Estamos buscando expandir nossa oferta de produtos para incluir produtos diferentes.
Esse novo design de rascunho é assim:
Product product_[type] product_attribute_[name]
---------------- ---------------- ----------------------------
part_number (PK) part_number (FK) attributeId (PK)
UPC specific_attr1 (FK) attribute_name
price specific_attr2 (FK)
... ...
Eu tenho uma pergunta sobre as tabelas de atributos do produto. A idéia aqui é que um produto possa ter uma lista de atributos, como cor: vermelho, verde, azul ou material: plástico, madeira, cromo, alumínio, etc.
Essa lista seria armazenada em uma tabela e a chave primária (PK) para esse item de atributo será usada na tabela específica do produto como uma chave estrangeira (FK).
(O livro Patterns of Enterprise Application Architecture, de Martin Fowler, chama isso de " Mapeamento de Chave Estrangeira ")
Isso permite que uma interface de site puxe a lista de atributos para um determinado tipo de atributo e cuspa em um menu suspenso ou em outro elemento da interface do usuário. Essa lista pode ser considerada uma lista "autorizada" de valores de atributo.
O número de junções que acaba acontecendo ao puxar um produto específico parece excessivo para mim. Você deve associar todas as tabelas de atributos do produto ao produto para poder obter os campos desse atributo. Geralmente, esse campo pode ser apenas uma string (varchar) para seu nome.
Esse padrão de design acaba criando um grande número de tabelas, assim como você acaba com uma tabela para cada atributo. Uma idéia para neutralizar isso seria criar algo mais como uma tabela de “sacolas” para todos os atributos do produto. Algo assim:
product_attribute
----------------
attributeId (PK)
name
field_name
Dessa forma, sua tabela pode ficar assim:
1 red color
2 blue color
3 chrome material
4 plastic material
5 yellow color
6 x-large size
Isso pode ajudar a reduzir a fluência da tabela, mas não reduz o número de junções e parece um pouco errado combinar tantos tipos diferentes em uma única tabela. Mas você seria capaz de obter todos os atributos de "cores" disponíveis com bastante facilidade.
No entanto, pode haver um atributo que tenha mais campos do que apenas "nome", como o valor RGB de uma cor. Isso exigiria que esse atributo específico possuísse outra tabela ou um único campo para o nome: par de valores (que possui suas próprias desvantagens).
O último padrão de design em que posso pensar é armazenar o valor real do atributo na tabela específica do produto e não ter uma "tabela de atributos". Algo assim:
Product product_[type]
---------------- ----------------
part_number (PK) part_number (FK)
UPC specific_attr1
price specific_attr2
... ...
Em vez de uma chave estrangeira para outra tabela, ela conteria o valor real, como:
part_number color material
----------- ----- --------
1234 red plastic
Isso eliminaria as junções e impediria a fluência da tabela (talvez?). No entanto, isso evita ter uma "lista autorizada" de atributos. Você pode retornar todos os valores inseridos no momento para um determinado campo (por exemplo: cor), mas isso também elimina a idéia de ter uma "lista autorizada" de valores para um determinado atributo.
Para ter essa lista, você ainda precisa criar uma tabela de atributos "grab bag" ou ter várias tabelas (subida de tabela) para cada atributo.
Isso cria a maior desvantagem (e por que eu nunca usei essa abordagem) de agora ter o nome do produto em vários locais.
Se você tiver o valor de cor "vermelho" na "tabela de atributos principais" e também armazená-lo na tabela "produto_ [tipo]", uma atualização na tabela "principal" causará um possível problema de integridade de dados se o aplicativo não atualize todos os registros com o valor antigo na tabela "product_type" também.
Então, após minha longa explicação e análise sobre esse cenário, percebo que esse não pode ser um cenário incomum e pode haver até um nome para esse tipo de situação.
Existem soluções geralmente aceitas para esse desafio de design? O número potencialmente grande de junções é aceitável se as tabelas forem relativamente pequenas? O armazenamento do nome do atributo, em vez de um atributo PK, é aceitável em alguma situação? Existe outra solução em que não estou pensando?
Algumas notas sobre o banco de dados / aplicativo deste produto:
- Os produtos não são atualizados / adicionados / removidos com frequência
- Os atributos não são atualizados / adicionados / removidos com frequência
- A tabela é mais frequentemente consultada para ler / retornar informações
- O cache do servidor está ativado para armazenar em cache o resultado de uma determinada consulta / resultado
- Pretendo começar com apenas um tipo de produto e estender / adicionar outros ao longo do tempo e terei potencialmente mais de 10 tipos diferentes