tabela única com colunas extras vs várias tabelas que duplicam o esquema


13

Estou trabalhando em um projeto em que, em algum momento, eu precisava tomar uma decisão sobre se, no banco de dados, eu deveria ter uma única tabela com várias colunas que nem todo registro usa ou várias tabelas com esquema duplicado.

Estou criando um aplicativo de informações esportivas que pode lidar com vários esportes. Podemos lidar com NBA, NHL, MLB, NFL, por exemplo. Cada esporte tem conceitos muito semelhantes - Times, Horários, Lesões, Informações do Jogador.

Nossa fonte de dados, é claro, não nos fornece cada dado no mesmo esquema. Cada esporte tem um esquema diferente para o qual recebemos dados de nosso fornecedor.

Como não havia tempo suficiente (demandas dos clientes) para fazer uma análise inicial dos feeds de dados para determinar pontos em comum, fiz uma hedge da minha aposta e fiz a 'aposta segura' e criei tabelas separadas individuais para cada esporte, em vez de um conjunto de tabelas que todos esportes usados.

O resultado é um esquema duplicado em várias tabelas e, portanto, interfaces duplicadas para o banco de dados (por exemplo, procs armazenados). Eu tenho algo como NBA_Game, NFL_Game, NBA_Team, NFL_Team, etc. Cada tabela pode ter algumas propriedades que a outra não possui e várias que são compartilhadas. continua por, digamos, 5 a 10 mesas em 4 ou 5 esportes. Ainda não tenho certeza se isso é algo totalmente ruim - a alternativa, com um único conjunto de tabelas com propriedades que nem todos os esportes usariam, poderia, por si só, também ser difícil de manejar.

Alguém que já fez isso encontrou armadilhas desse tipo de design e poderia compartilhar sua experiência aqui? Coisas que podem me ajudar a saber agora em vez de aprender da maneira mais difícil no caminho? Você fez o contrário, com uma grande tabela / conjunto de tabelas, com colunas que nem todos os registros usariam? Que armadilhas você teve que fazer isso?

Existe alguma alternativa, como herança de tabela que você usou no passado, que funcionou melhor?

obrigado

Respostas:


12

Por fim, tudo se resume ao uso e à arquitetura.

Arquitetura

O sistema lida com "qualquer esporte"? A idéia que você colocou no seu chapéu de astronauta de arquitetura e construiu um sistema genérico que pode lidar com qualquer tipo futuro de esporte que talvez nem exista hoje?

Nesse caso, obviamente, ter tabelas nomeadas dinamicamente é uma grande dor; portanto, faria sentido ter um esquema que suporte n esportes, se necessário.

Dito isto, tenho um viés muito forte contra essa abordagem: quase sempre é mais trabalho e leva a resultados mais ruins. Criar uma interface do usuário, esquema etc. para cada esporte resultará em melhor experiência do usuário e mais fácil manutenção do código, mesmo que isso signifique uma quantidade superficial de duplicação (como evitar / minimizar isso é uma pergunta à parte).

Como você lida com jogadores que praticam vários esportes? Eles recebem duas entradas (por exemplo, você trata como pessoas diferentes) ou você está tentando fazer algo específico com elas?

Usar

Então, vamos supor que você não pratica esportes dinamicamente (por exemplo, se alguém quiser adicionar um novo esporte, é necessário um esforço de desenvolvimento para adicioná-lo).

Existe um momento em que você exibe jogadores (ou qualquer outro objeto que você mencionou) de mais de um esporte por vez?

Eu pude ver isso em uma função de pesquisa, na qual era possível pesquisar pelo nome do jogador ou da equipe (independentemente do esporte), mas além disso, não consigo imaginar muitos casos de uso.

Se você nunca precisar fazer isso, sua abordagem será perfeitamente adequada. Você pode parar de ler aqui.

Esquemas Alternativos

Visualizações

Sou fã do KISS. Em mais de 15 anos de desenvolvimento de software, continuo voltando à filosofia "construir a coisa mais simples que funciona".

Portanto, minha reação inicial, assumindo que uma função de pesquisa entre esportes é realmente o único caso de uso, é criar visualizações:

SELECT PlayerName, 'NFL' as [Sport], TeamName FROM NFL_Players JOIN NFL_Teams ... 
UNION  
SELECT PlayerName, 'NHL' as [Sport], TeamName FROM NHL_Players JOIN NHL_Teams ... 
UNION ....

Obviamente, se você adicionar um novo esporte, precisará adicionar à exibição. Também pode ser útil incluir outras informações comuns, mas realmente depende do que precisa ser mostrado.

Eu tentaria manter todo o material específico do esporte na definição de visualização, para que o código de pesquisa não precise ter muito ou nenhum código específico (além de talvez saber como vincular ao /nhl/players/player-namevs/nfl/... ou como seu aplicativo faz isso).

Herança de Tabela

A herança de tabela pode funcionar, mas é bastante complexa. Não tenho muita experiência com isso e, de fato, acho que toda vez que me envolvo em avaliá-lo, acabamos fazendo algo mais simples (como sugeri aqui).

Então, pessoalmente, ainda não descobri por que isso seria útil, mas talvez haja um caso de uso convincente (que eu não conheça) que justifique a complexidade (por exemplo, a herança da tabela resolve o caso de uso melhor do que qualquer outra solução) .

Tabelas separadas para atributos específicos do esporte

Você pode playerscriar uma única tabela que possua atributos comuns a todos os jogadores de todos os esportes e, em seguida, outro conjunto de tabelas comonhl_players_details essa contém um playerId e colunas com informações adicionais sobre o jogador. Se houver muitos atributos comuns ou você tiver muitos usos de "todos os jogadores de todos os esportes", isso poderá fazer sentido.

Pares de valores-chave para atributos específicos do esporte

Abordagem completamente alternativa: ter uma playersmesa (mais uma vez, com atributos comuns como nome) e, em seguida, uma player_datatabela que tem PlayerId, Sport, Attribute, Value. Os nomes dos atributos inseridos seriam específicos do esporte. Isso permite que você adicione essencialmente novos atributos sem modificar o esquema (seu código ainda precisará saber para carregá-los / exibi-los, é claro). A desvantagem é que você perde alguma integridade: o valor normalmente seria um campo de cadeia de caracteres, portanto, o código do seu aplicativo precisaria ser resiliente e lidar com possíveis falhas na conversão da cadeia de caracteresvalue de em um tipo de dados específico (como número inteiro).

É claro que esse conceito pode se aplicar a equipes, jogos etc.


Procurar uma solução para um projeto herdado terá vários tipos e tabelas autenticáveis, a menção de visões aqui, das quais eu havia esquecido, realmente ajudou a oferecer outra solução possível para minha pesquisa. Obrigado.
FullStackFool 15/08/19

5

Você está falando sobre normalização do banco de dados . Você pode ficar aliviado ao saber que não existe um modelo de dados perfeito e que mais normalização nem sempre é melhor. A normalização pode impor custos em termos de clareza do modelo de dados e desempenho do banco de dados. Portanto, o melhor modelo para selecionar dependerá dos seus requisitos de uso.

Aparentemente, seus exemplos parecem bastante semelhantes em conceito (X_Game vs Y_Game e X_Team vs Y_Team) para que a sobrecarga extra de algumas colunas não pareça irracional. Dito isto, se cada esporte adicionar várias dúzias de colunas extras à mesa, seria realmente complicado.

Nesse caso, você pode considerar um modelo híbrido, no qual os dados comuns são mantidos em uma tabela central, mas os dados específicos do esporte são mantidos em uma estrutura de dados vinculada. Algo como:

table Game {
    gameId int,
    teamId1 int fk,
    teamId2 int fk
}

table HockeyGame {
    gameId int fk,
    penaltyMinutes int
}

table BasketballGame {
    gameId int fk,
    freeThrows int
}

Era isso que eu ia propor, além de talvez uma coluna na tabela Jogo indicando o tipo de jogo. Percebo que isso pode ser inferido ao entrar nas outras mesas, mas se o número de tipos de jogos aumentar, isso começa a ficar entediante.
Rory Hunter

Absolutamente - este é apenas um modelo básico para ilustrar os principais relacionamentos e alguns exemplos do que podem ser dados comuns versus dados específicos do esporte.
Midnotion
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.