Existem duas tabelas: Deal
e DealCategories
. Uma oferta pode ter muitas categorias de ofertas.
Portanto, a maneira correta deve ser criar uma tabela chamada DealCategories
com a seguinte estrutura:
DealCategoryId (PK)
DealId (FK)
DealCategoryId (FK)
No entanto, nossa equipe de terceirização armazenou as várias categorias no Deal
tabela da seguinte maneira:
DealId (PK)
DealCategory -- In here they store multiple deal ids separated by commas like this: 18,25,32.
Sinto que o que eles fizeram está errado, mas não sei como explicar claramente por que isso não está certo.
Como devo explicar a eles que isso está errado? Ou talvez eu seja a pessoa que está errada e isso é aceitável?
database-design
foreign-key
Sarawut Positwinyu
fonte
fonte
Respostas:
Sim, é uma péssima ideia.
Ao invés de ir:
Agora você precisa ir:
Em seguida, é necessário fazer algumas coisas no código do aplicativo para dividir a lista de vírgulas em números individuais e, em seguida, consultar o banco de dados separadamente:
Esse antipadrão de design deriva de um completo mal-entendido da modelagem relacional (você não precisa ter medo de tabelas. As tabelas são suas amigas. Use-as) ou uma crença estranhamente equivocada de que é mais rápido pegar uma lista separada por vírgula e dividi-la no código do aplicativo do que é adicionar uma tabela de links ( nunca é). A terceira opção é que eles não são confiantes / competentes o suficiente com o SQL para poder configurar chaves estrangeiras, mas se for esse o caso, eles não devem ter nada a ver com o design de um modelo relacional.
Antipatterns do SQL (Karwin, 2010) dedica um capítulo inteiro a esse antipattern (que ele chama de 'Jaywalking'), páginas 15-23. Além disso, o autor postou uma pergunta semelhante no SO . Os principais pontos que ele observa (conforme aplicado a este exemplo) são:
COUNT
,SUM
etc), mais uma vez, variam de 'complicado' para 'quase impossível'. Pergunte aos desenvolvedores como eles obteriam uma lista de todas as categorias com uma contagem do número de transações nessa categoria. Com um design adequado, são quatro linhas de SQL.VARCHAR
limitações de tamanho da lista. Embora se você tiver uma lista separada por vírgulas com mais de 4000 caracteres, é provável que esteja analisando que o monstro será lento como o inferno de qualquer maneira.TLDR: é um design fundamentalmente defeituoso, não aumenta com escala, introduz complexidade adicional até para as consultas mais simples e, logo após a instalação, torna o aplicativo mais lento.
fonte
Na verdade, é um bom design se você precisar apenas consultar as categorias para um determinado negócio.
Mas é terrível se você quiser conhecer todas as ofertas em uma determinada categoria.
E também torna muito difícil e propenso a erros fazer qualquer outra coisa - como atualizações, contagens, associações, etc.
A desnormalização tem seu lugar, mas você deve ter em mente que ela otimiza para um tipo de consulta às custas de todas as outras que você pode fazer com os mesmos dados. Se você souber que sempre estará consultando um padrão, poderá ser uma vantagem usar o design desnormalizado. Mas se houver alguma chance de você precisar de mais flexibilidade nos tipos de consultas, use um design normalizado.
Como qualquer outra forma de otimização, você precisa saber quais consultas serão executadas antes de decidir se a desnormalização é justificada.
fonte
select * from DealCategories where DealId in (1,2,3,4,...)
. Você tem mais experiência em relação ao design do banco de dados do que eu; talvez, em alguns casos, tenha boas razões para esse "ajuste extremo" em casos muito específicos. Minha única idéia para justificar isso é umaselect
carga muito alta em Deal / DealCategory. Isso me parece muito com alguma equipe de terceirização sem nenhum conhecimento em design de banco de dados, além de criar tabelas, a criou.Vários valores em uma coluna são contra a 1ª forma normal.
Também não há ganho de velocidade, pois as tabelas devem ser vinculadas no banco de dados. Você deve ler e analisar uma string primeiro e, em seguida, selecione todas as categorias para o "Negócio".
A implementação correta seria uma tabela de junção como "DealDealCategories", com DealId e DealCategoryId.
Implementação de má hierarquia?
Além disso, um FK em DealCategories para outra DealCategory parece uma implementação ruim de uma hierarquia / árvore de DealCategories. Trabalhar com árvores por meio de uma relação de identificação dos pais (chamada lista de adjacências) é um problema!
Verifique se há conjuntos aninhados (de boa leitura, mas difíceis de modificar) e tabelas de fechamento (melhor desempenho geral, mas possivelmente alto uso de memória - provavelmente não muito para suas DealCategories) ao implementar hierarquias!
fonte