Você tem pelo menos essas cinco opções para modelar a hierarquia de tipos que você descreve:
Herança de tabela única : uma tabela para todos os tipos de produtos, com colunas suficientes para armazenar todos os atributos de todos os tipos. Isso significa muitas colunas, a maioria das quais é NULL em qualquer linha.
Herança de tabela de classe : uma tabela para produtos, armazenando atributos comuns a todos os tipos de produtos. Em seguida, uma tabela por tipo de produto, armazenando atributos específicos para esse tipo de produto.
Herança de tabela concreta : nenhuma tabela para atributos comuns de produtos. Em vez disso, uma tabela por tipo de produto, armazenando atributos comuns do produto e atributos específicos do produto.
LOB serializado : uma tabela para produtos, armazenando atributos comuns a todos os tipos de produtos. Uma coluna extra armazena um BLOB de dados semiestruturados, em XML, YAML, JSON ou algum outro formato. Este BLOB permite armazenar os atributos específicos para cada tipo de produto. Você pode usar padrões de design sofisticados para descrever isso, como Fachada e Memento. Mas, independentemente de você ter um blob de atributos que não podem ser consultados facilmente no SQL; você precisa buscar o blob inteiro no aplicativo e classificá-lo por aí.
Valor de atributo da entidade : uma tabela para produtos e uma tabela que atribui atributos a linhas, em vez de colunas. O EAV não é um design válido em relação ao paradigma relacional, mas muitas pessoas o usam de qualquer maneira. Este é o "Padrão de propriedades" mencionado por outra resposta. Veja outras perguntas com a tag eav no StackOverflow para obter algumas das armadilhas.
Escrevi mais sobre isso em uma apresentação, Extensible Data Modeling .
Pensamentos adicionais sobre o EAV: Embora muitas pessoas pareçam favorecer o EAV, eu não. Parece a solução mais flexível e, portanto, a melhor. No entanto, lembre-se do ditado TANSTAAFL . Aqui estão algumas das desvantagens do EAV:
- Não há como tornar uma coluna obrigatória (equivalente a
NOT NULL
).
- Não há como usar tipos de dados SQL para validar entradas.
- Não há como garantir que os nomes dos atributos sejam digitados de forma consistente.
- Não há como colocar uma chave estrangeira nos valores de qualquer atributo, por exemplo, para uma tabela de pesquisa.
- A busca de resultados em um layout tabular convencional é complexa e dispendiosa, porque para obter atributos de várias linhas, você precisa fazer
JOIN
para cada atributo.
O grau de flexibilidade que o EAV oferece exige sacrifícios em outras áreas, provavelmente tornando seu código tão complexo (ou pior) do que teria sido para resolver o problema original de uma maneira mais convencional.
E na maioria dos casos, é desnecessário ter esse grau de flexibilidade. Na pergunta do OP sobre tipos de produtos, é muito mais simples criar uma tabela por tipo de produto para atributos específicos do produto, para que você tenha uma estrutura consistente imposta pelo menos para entradas do mesmo tipo de produto.
Eu usaria o EAV apenas se todas as linhas tiverem potencial para ter um conjunto distinto de atributos. Quando você tem um conjunto finito de tipos de produtos, o EAV é um exagero. Herança de tabela de classe seria minha primeira escolha.
Atualização 2019: quanto mais vejo as pessoas usando o JSON como uma solução para o problema de "muitos atributos personalizados", menos eu gosto dessa solução. Isso torna as consultas muito complexas, mesmo ao usar funções JSON especiais para suportá-las. É necessário muito mais espaço de armazenamento para armazenar documentos JSON, em vez de armazenar em linhas e colunas normais.
Basicamente, nenhuma dessas soluções é fácil ou eficiente em um banco de dados relacional. Toda a idéia de ter "atributos variáveis" está fundamentalmente em desacordo com a teoria relacional.
O que se resume é que você precisa escolher uma das soluções com base nas que são menos ruins para o seu aplicativo. Portanto, você precisa saber como vai consultar os dados antes de escolher um design de banco de dados. Não há como escolher uma solução que seja "melhor" porque qualquer uma das soluções pode ser a melhor para um determinado aplicativo.
@Coração de pedra
Eu iria aqui com EAV e MVC todo o caminho.
@Bill Karvin
Todas as coisas que você mencionou aqui:
na minha opinião, não pertence a nenhum banco de dados porque nenhum deles é capaz de lidar com essas interações e requisitos em um nível adequado, como a linguagem de programação de um aplicativo.
Na minha opinião, usar um banco de dados dessa maneira é como usar uma pedra para martelar um prego. Você pode fazer isso com uma pedra, mas não deve usar um martelo mais preciso e projetado especificamente para esse tipo de atividade?
Esse problema pode ser resolvido fazendo poucas consultas sobre dados parciais e processando-as no layout tabular com seu aplicativo. Mesmo se você tiver 600 GB de dados do produto, poderá processá-los em lotes se precisar de dados de todas as linhas desta tabela.
Indo além Se você deseja melhorar o desempenho das consultas, pode selecionar determinadas operações como, por exemplo, relatórios ou pesquisa de texto global e preparar para elas tabelas de índice que armazenariam os dados necessários e seriam regenerados periodicamente, digamos a cada 30 minutos.
Você nem precisa se preocupar com o custo de armazenamento de dados extra, porque fica cada vez mais barato a cada dia.
Se você ainda se preocupa com o desempenho das operações realizadas pelo aplicativo, sempre pode usar o Erlang, C ++, Go Language para pré-processar os dados e, posteriormente, apenas processar os dados otimizados no aplicativo principal.
fonte
you can always use Erlang, C++, Go Language to pre-process the data
O que você quis dizer? Em vez de DB, use Go lang? Você poderia por favor explicar isso?Se eu usar
Class Table Inheritance
significado:Que eu mais gosto das sugestões de Bill Karwin. Posso prever uma desvantagem, que tentarei explicar como evitar que se torne um problema.
Qual plano de contingência devo ter quando um atributo que é comum apenas a 1 tipo e depois se torna comum a 2 e depois a 3 etc.?
Por exemplo: (este é apenas um exemplo, não é meu problema real)
Se vendermos móveis, poderemos vender cadeiras, luminárias, sofás, TVs etc. O tipo de TV pode ser o único tipo que carregamos que consome energia. Então, eu colocaria o
power_consumption
atributo notv_type_table
. Mas então começamos a transportar sistemas de home theater que também possuem umapower_consumption
propriedade. OK, é apenas mais um produto. Por isso, adicionarei esse campostereo_type_table
, pois provavelmente é o mais fácil neste momento. Mas, com o tempo, à medida que começamos a transportar mais e mais eletrônicos, percebemos quepower_consumption
é amplo o suficiente para estar nomain_product_table
. O que eu deveria fazer agora?Adicione o campo ao
main_product_table
. Escreva um script para percorrer os componentes eletrônicos e coloque o valor correto de cada umtype_table
para omain_product_table
. Em seguida, solte essa coluna de cada umatype_table
.Agora, se eu estivesse sempre usando a mesma
GetProductData
classe para interagir com o banco de dados e obter as informações do produto; então, se qualquer alteração no código precisar agora de refatoração, elas devem ser apenas para essa classe.fonte
Você pode ter uma tabela Produto e uma tabela ProductAdditionInfo separada com 3 colunas: ID do produto, nome da informação adicional, valor da informação adicional. Se a cor for usada por muitos, mas nem todos os tipos de produtos, você poderá fazer com que seja uma coluna anulável na tabela Produto ou apenas colocá-la em ProductAdditionalInfo.
Essa abordagem não é uma técnica tradicional para um banco de dados relacional, mas vi que ele era muito usado na prática. Pode ser flexível e ter bom desempenho.
Steve Yegge chama esse padrão de Propriedades e escreveu um longo post sobre como usá-lo.
fonte
3 columns: product ID, additional info name, additional info value
eu entendi o conceito. E eu já fiz isso antes e tive problemas. No entanto, não me lembro no momento quais eram esses problemas.