web-dev-qa-db-fra.com

Table simple avec / Extra Colonnes vs Tables multiples qui dupliquent le schéma

Je travaille sur un projet où, à un moment donné, je devais prendre une décision sur la base de la base de données, je devrais avoir une table unique avec plusieurs colonnes qui n'utilisent pas tous les enregistrements, ni de multiples tables avec schéma dupliqué.

Je crée une application d'information sportive pouvant gérer plusieurs sports. Nous pouvons gérer NBA, NHL, MLB, NFL, par exemple. Chaque sport a des concepts très similaires - des équipes, des horaires, des blessures, des informations sur le joueur ..

Notre source de données ne nous donne pas chaque morceau de données dans le même schéma. Chaque sport a un schéma différent auquel nous recevons des données de notre fournisseur.

Parce qu'il n'y avait pas assez de temps (demandes de clients) pour faire une analyse initiale des flux de données afin de déterminer les points communs, j'ai couvert mon pari et a pris le "pari sûr" et a créé des tables distinctes individuelles pour chaque sport au lieu d'un ensemble de tables que tous. Sports utilisés.

Le résultat est le schéma dupliqué dans plusieurs des tables, et des interfaces de duplication de la base de données (par exemple Procs stockés). J'ai quelque chose comme nba_game, nfl_game, nba_team, nfl_team, etc. Chaque table peut avoir quelques propriétés que l'autre ne le fait pas, et plusieurs qui sont partagés. Il continue à dire 5-10 tables sur 4 ou 5 sports. Je ne suis toujours pas sûr que cela soit tout à fait une mauvaise chose - l'alternative, ayant un seul ensemble de tables qui possédait des propriétés sur celui-ci que tous les sports n'utiliseraient pas, pourraient avoir de son caractère difficile à manier.

Est-ce que quelqu'un qui a fait cela a fait cela dans des pièges de ce type de conception et pourrait partager leur expérience ici? Des choses qui pourraient m'aider à savoir maintenant au lieu d'apprendre la route difficile sur la route? L'avez-vous fait l'inverse, ayant une grande table/ensemble de tables, avec des colonnes que tous les enregistrements n'utiliseraient pas? Quels pièges avez-vous rencontré cela?

Y a-t-il une alternative telle que héritage de table que vous avez utilisée dans le passé qui fonctionnait mieux?

Merci

13
dferraro

En fin de compte, cela revient à l'utilisation et à l'architecture.

Architecture

Le système gère-t-il "tout sport"? Est-ce que l'idée que vous mettez votre chapeau d'astronaute d'architecture et construisez un système générique capable de gérer tout type de sport futur qui pourrait même exister aujourd'hui?

Si oui, évidemment, avoir des tables nommées dynamiquement est une douleur énorme, il serait donc logique d'avoir un schéma qui soutient N Sports, si nécessaire.

Cela dit, j'ai un biais très fort contre cette approche: c'est presque toujours plus de travail et conduit à des résultats les plus pauvres. Faire une interface utilisateur distincte, un schéma, etc. pour chaque sport conduira finalement à une meilleure expérience utilisateur et plus facile à maintenir le code, même si cela signifie une quantité superficielle de duplication (comment éviter/minimiser cela est une question distincte).

Comment gérez-vous des joueurs qui jouent plusieurs sports? Ont-ils deux entrées (par exemple, vous traitez comme des personnes différentes) ou essayez-vous de faire quelque chose de spécifique avec eux?

Utilisation

Alors supposons que vous ne faites pas de sport de manière dynamique (par exemple, si quelqu'un veut ajouter un nouveau sport, cela nécessite des efforts de développement pour l'ajouter).

Y a-t-il déjà un temps où vous affichez des joueurs (ou tout autre objet que vous avez mentionné) de plus d'un sport à la fois?

Je pouvais voir cela pour une fonction de recherche, où vous pourriez rechercher par le joueur ou le nom d'équipe (quel que soit le sport), mais au-delà de cela, je ne peux pas imaginer de nombreux cas d'utilisation.

Si vous n'avez jamais besoin de faire cela, votre approche est parfaitement bien. Vous pouvez arrêter de lire ici.

Schemas alternatifs

Vues

Je suis fan de Kiss. En plus de 15 ans de développement de logiciels, je continue de revenir à la philosophie "construire la chose la plus simple qui fonctionne".

Donc, ma réaction initiale, en supposant qu'une fonction de recherche croisée est vraiment le seul cas d'utilisation, est de créer des vues:

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 ....

Bien sûr, si vous ajoutez un nouveau sport, vous devez ajouter à la vue. Il peut également être utile d'inclure d'autres informations courantes, mais qui dépend vraiment de ce qui doit être montré.

J'essaierais de garder toutes les choses spécifiques au sport dans la définition de la vue. Le code de recherche n'a donc pas besoin d'avoir beaucoup ou un code spécifique (en plus de savoir peut-être savoir comment créer un lien vers /nhl/players/player-name vs /nfl/... ou quelle que soit votre application cela).

Hérité de la table

L'héritage de la table peut fonctionner, mais est assez complexe. Je n'ai pas de tonne d'expérience avec elle et, en fait, je pense que chaque fois que je suis impliqué dans l'évaluation, nous avons fini par faire quelque chose de plus simple (comme je suggère ici).

Donc, personnellement, je n'ai pas encore trouvé pourquoi cela serait utile, mais il y a peut-être un cas d'utilisation convaincante (que je ne savais pas) qui justifie la complexité (par exemple, le héritage de la table résout le cas d'utilisation mieux que toute autre solution) .

Tables séparées pour les attributs spécifiques au sport

Vous pouvez faire une seule table players qui a des attributs communs à tous les joueurs de tous les sports, puis un autre ensemble de tables comme nhl_players_details qui contient une playerid et des colonnes avec des informations supplémentaires sur le lecteur. S'il y a une tonne d'attributs communs, vous avez de nombreuses utilisations de "tous les joueurs de tous les sports", alors cela peut avoir un sens.

Valeur de la valeur clé pour attributs spécifiques au sport

Approche complètement alternative: avoir une table players (à nouveau, avec des attributs communs tels que le nom), puis un player_data table qui a PlayerId, Sport, Attribute, Value. Les noms d'attributs entrés seraient spécifiques au sport. Cela vous permet d'ajouter essentiellement de nouveaux attributs sans modifier le schéma (votre code aurait toujours besoin de savoir le charger/les afficher bien sûr). L'inconvénient est que vous perdez une certaine intégrité: la valeur serait généralement un champ de chaîne. Votre code d'application devrait donc être résilient et gérer les défaillances potentielles convertissant la chaîne value à un type de données spécifique (comme entier).

Ce concept peut bien sûr s'appliquer aux équipes, aux jeux, etc.

12
gregmac

Vous parlez de normalisation de la base de données . Vous pouvez être soulagé d'apprendre qu'il n'y a pas de modèle de données parfait, et que plus de normalisation n'est pas toujours meilleure. La normalisation peut imposer des coûts en termes de clarté du modèle de données et de la performance de la base de données. Par conséquent, le meilleur Le modèle à sélectionner dépendra de vos exigences d'utilisation.

Sur la surface, vos exemples semblent assez similaires dans le concept (x_game vs y_game et x_team vs y_team) que les frais généraux supplémentaires de quelques colonnes ne semblent pas déraisonnables. Cela dit, si chaque sport va ajouter plusieurs dizaines de colonnes supplémentaires à la table, elle serait vraiment difficile à manier.

Dans ce cas, vous voudrez peut-être envisager un modèle hybride, où les données communes sont conservées dans une table centrale, mais des données spécifiques au sport sont conservées dans une structure de données liée. Quelque chose comme:

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

table HockeyGame {
    gameId int fk,
    penaltyMinutes int
}

table BasketballGame {
    gameId int fk,
    freeThrows int
}
5
Midnotion