Estou desenvolvendo uma ferramenta que lida com peças (elétricas). As peças podem ser criadas, visualizadas, modificadas, excluídas, agrupadas e assim por diante ...
Para tornar essa pergunta útil para futuros visitantes, eu gostaria de manter essa pergunta universal, pois o gerenciamento de partes em um banco de dados é muito comum, independentemente de quais partes estejam no banco de dados (CDs, carros, comida, estudantes, ...).
Estou pensando em três projetos diferentes de banco de dados:
Usando uma tabela de peças e tabelas derivadas para atributos de peças especializados.
Parts (id, part_type_id, name) PartTypes (id, name) Wires (id, part_id, lenght, diameter, material) Contacts (id, part_id, description, picture)
Usando apenas tabelas de peças especializadas.
Wires (id, name, lenght, diameter, material) Contacts (id, name, description, picture)
Usando uma tabela Parts-, PartTypes-, ValueTypes- e PartValues que contêm todos os valores.
PartTypes (id, name) ValueTypes (id, part_type_id, name) Parts (id, part_type_id, name) PartValues (part_id, value_type_id, value)
Qual prefere e por quê? Ou existe um melhor?
Estou preocupado com as consultas ao banco de dados. Não quero que as consultas se tornem muito lentas ou complicadas.
Atualizar
O número de tipos no banco de dados é praticamente dado e estático, pois se baseia em um padrão internacional e será aprimorado raramente.
fonte
Respostas:
Opção 3 : (algumas vezes) a
opção 3 é o design "EAV" . Em teoria, é bom porque os campos são retirados da estrutura da tabela e se tornam dados. Mas dá um desempenho terrível. Também não permite o uso de indexação adequada. E isso torna as consultas muito mais complicadas.
Eu usaria apenas o EAV em circunstâncias especiais. Eu usei o EAV para calcular as peças auxiliares necessárias para os pedidos e funcionou bem. Mas esteja muito cansado de usá-lo como design para suas tabelas principais.
Opção 2 : (nunca?) A
opção 2 é um não não. E os campos compartilhados? Você duplicará a estrutura da tabela para cada campo compartilhado? Isso exigiria a inclusão de sindicatos nos relatórios de todo o sistema.
Opção 1 : (vencedor!) A
opção 1 pode parecer um pouco básica demais, mas provavelmente é a melhor aposta para suas tabelas principais. Todas as partes usam a mesma tabela mestre para campos compartilhados, evitando assim uniões em seus relatórios. Possui ótimo desempenho, permitindo o uso adequado da indexação. As consultas são no estilo tradicional e são simples.
A desvantagem da opção 1 é que você não pode adicionar campos dinamicamente. Mas você realmente quer? Ao adicionar campos dinamicamente, você está executando o design do banco de dados em tempo de execução.
fonte
Eu tenderia a não opção # 3.
A opção 3 é a configuração do par nome-valor que viola a normalização.
Idealmente, tenta-se ter algum nível de normalização do banco de dados. Busque a normalização completa e desnormalize conforme necessário quando for identificado para problemas de customização ou desempenho.
Considere a consulta "qual é o nome e o ID da peça para todos os fios de cobre"
A estrutura nº 1 é
A estrutura 2 é
A estrutura 3 é
Considere também a complicação de inserções e exclusões do sistema.
Algumas leituras adicionais sobre por que não # 3 - A maldição do par de valores de nomes
fonte
part_type_id = part_types.id
evalue_types.id = part_values.type_value_id
são ambas cláusulas de junção, deixando a onde para onde o tipo de peça é wire, o tipo de valor é material e o valor é cobre que é relativamente sucintaEu vou opção 3
A opção 1 é ruim porque você não deseja que suas junções sejam baseadas em um valor arquivado. (ie
If type ="Wire" join to TblWire
)A opção 2 é ruim porque você não tem como relatar seu inventário como um todo
fonte
Eu começaria com um modelo de dados / objetos que permitisse a herança e usaria um mapeamento objeto-relacional padrão . Dessa forma você obtém uma classe base
Parts
e sub-classes comoWires
,Contacts
etc. Agora, se você aplicar uma estratégia de "mapa-cada-classe-a-própria-table", você tem a opção 1, que é a solução mais "normalizado" e deve ser a estratégia canônica se você não tiver mais informações sobre as consultas que espera.A opção 2 é o que você obtém ao aplicar uma abordagem "mapear cada classe de concreto para a própria tabela". Isso pode evitar "junções" e pode ter um desempenho melhor de algum tipo se as consultas (especialmente consultas para apenas um "tipo de peça"), por outro lado, tornam o manuseio genérico com todas as peças mais difícil e mais lento. Evite isso se você não tiver motivos especiais para isso.
A opção 3 é o que você precisa apenas se desejar que o usuário altere o número de tipos de peças em tempo de execução - se você não espera esse requisito, a opção 3 será um exemplo perfeito para coisas com excesso de engenharia.
fonte
Com o banco de dados NOSQL DB (como o MongoDB, por exemplo), você precisará apenas de um conjunto denominado "Parts". Cada parte desse conjunto é denominada documento - registro com conjunto de campos variável:
Eu acho que esse é o armazenamento de dados mais natural para a tarefa que você descreve.
fonte
Definitivamente, vá com a opção 1, mas com algumas modificações muito simples:
Em seguida, você pode usar restrições CHECK e valores DEFAULT para garantir que o part_type_id esteja correto e, em seguida, você pode ingressar em part_type_id e part_id. Isso evita ter uma associação condicional com base em apenas uma tabela e, se você precisar adicionar um part_type_id aos fios (digamos que estamos subdividindo essa parte e adicionando outra tabela de atributos estendidos), as restrições padrão e de verificação podem ser alteradas.
fonte
wires.id
econtacts.id
como a(part_id, part_type_id)
combinação será suficiente para identificar inequivocamente uma parte.A opção 3 é mais genérica e pode acomodar mais casos de uso.
Na opção 3, você pode precisar de mais junções e consultas complexas para recursos simples; na opção 2, você precisa de consultas complexas para recursos "grandes", como inventário e relatórios, e pode precisar de uniões para fazer isso.
Você sempre pode simplificar suas consultas nas opções 3 usando Views, se muitas vezes precisar apenas do Wire ou Contact, faça uma View para cada uma delas. Você pode otimizá-lo se for necessário.
fonte