web-dev-qa-db-fra.com

Le stockage d'une liste de chaînes dans un seul champ de base de données est-il une mauvaise idée? Pourquoi?

Récemment, j'ai commencé à travailler sur un système hérité. Les personnes qui l'ont développé ont eu l'idée de stocker la liste des chaînes dans un seul champ de la table de base de données. Disons que c'est un identifiant pour un objet qui n'a pas de représentation ni de données dans la base de données. La gamme de ces identifiants sera relativement petite en production.

D'un autre côté, mes intuitions et mon "bon goût de conception" m'indiquent qu'il devrait être représenté dans un tableau séparé (similaire à un tableau utilisé pour représenter des relations plusieurs-à-plusieurs).

Leur approche est-elle vraiment mauvaise et il vaudrait mieux commencer une refactorisation? Si oui, quelles mauvaises conséquences la conception originale peut-elle entraîner à l'avenir? Y a-t-il des principes de conception relationnelle qui expliquent cette approche?

Modifier pour répondre aux commentaires:

Comme je suppose, ils n'ont pas utilisé cette approche pour résoudre un problème spécifique comme la structuration hiérarchique d'une manière délicate. Le scénario le plus probable était le cas où ils travaillaient simplement sous la pression du temps et devaient mettre en œuvre de nouvelles fonctionnalités aussi rapidement que possible.

Je suis sûr qu'avant, le champ représentait une seule valeur. Ils allaient implémenter une fonctionnalité pour stocker plus d'une valeur et ont essayé d'éviter les migrations de base de données.

13
mpasko256

Le modèle de données n'est pas normalisé; pour qu'il en soit ainsi, il faudrait un tableau séparé comme vous le dites. À cet égard, ce n'est pas une bonne pratique de modélisation de données.

Il est difficile de déterminer si cela a été fait pour une bonne raison ou non. En théorie, la simplification du codage ou les performances peuvent avoir été des motivations. Il est probable que le champ contenait à l'origine un identifiant, les exigences ont changé et les développeurs n'ont pas eu le temps ni l'envie de recompacter.

Il est probablement plus important de savoir si vous devez ou non vous refactoriser. Dans des circonstances similaires, je ne refacturerais pas de manière préventive un cas comme celui-ci par défaut. Je considérerais cela si l'une des conditions suivantes s'appliquait:

  1. vous avez des preuves que cela cause des problèmes, par exemple à partir des journaux des problèmes hérités
  2. vous savez pertinemment que vous allez apporter des changements fonctionnels dans ce domaine
  3. le code qui gère les données est particulièrement complexe et difficile à raisonner.

Ce que je ferais, et TBH je recommanderais cela chaque fois que vous reprenez une application héritée, c'est de démarrer un wiki (ou équivalent) et de documenter des cas comme celui-ci. Par exemple,

  • les problèmes que vous avez trouvés tels que la ride de modelage de données
  • les changements que vous prévoyez de mettre en œuvre
  • les changements que vous ne prévoyez pas de mettre en œuvre mais le feraient s'il y avait du temps
  • domaines de code difficiles à raisonner
  • les zones de code que vous avez trouvé difficile à maintenir.

J'ai trouvé que c'est un aide-mémoire utile pour moi lorsque je travaille et/ou que je reviens à une base de code. Il peut également être très utile à votre successeur lorsqu'il doit à son tour commencer à apprendre la base de code.

16
Alex

Le stockage d'une liste de chaînes dans un seul champ de base de données est-il une mauvaise idée?

Il serait généralement considéré comme une violation de la normalisation.

Cependant, parfois, cette solution est utilisée pour résoudre un problème, par exemple dans la structuration hiérarchique, où une chaîne de chemin de longueur variable d'une certaine sorte représente la structure.

Parmi les problèmes avec une liste d'éléments dans une seule chaîne, on peut citer:

  • en requête, cela signifie utiliser des recherches de chaînes au lieu du calcul relationnel; l'indexation des données peut être problématique.
  • il y a la question de la signification de l'ordre des entrées dans la liste, et que vous ne pouvez probablement pas imposer quoi que ce soit sur l'ordre en tant que contrainte sur la base de données.
  • il y a le problème du caractère séparateur et le potentiel de problème d'échappement/de non-échappement des caractères avec les éléments individuels.
  • il existe un potentiel de doublons dans la même liste; encore une fois, cela découle de l'impossibilité d'appliquer directement les contraintes (bien qu'une fonction de déclenchement puisse peut-être vérifier les contraintes).
  • un seul élément seul est toujours une liste, mais peut être confondu car nous ne pouvons pas dire (ou demander) à la base de données que le vrai type est une liste. Cela peut être problématique si la plupart des lignes n'ont qu'un seul élément dans la liste, alors que certaines en ont plus d'un: il n'y a aucun moyen d'imposer une utilisation correcte de la colonne en tant que liste.
10
Erik Eidt

C'est un contre-modèle courant de le faire.

Vos exigences changent et vous avez maintenant besoin de plus de valeurs dans un endroit où vous n'en aviez besoin que d'une seule. Comme un livre n'a qu'un seul auteur non? Qui aurait pu deviner qu'un livre a plusieurs auteurs? Il s'agit d'un moyen simple de répondre à cette modification des exigences sans avoir à modifier le schéma de votre base de données.

Il y a cependant quelques inconvénients.

  • Les requêtes deviennent plus difficiles car vous avez maintenant des données d'identification combinées dans 1 champ.
  • Vous ne pouvez plus utiliser "=" mais vous devez utiliser quelque chose comme "like". Ce qui tuera les performances.
  • Vous perdez la possibilité de rejoindre ce domaine.
  • Essayez count/sum etc, cela ne fonctionnera pas.
  • La mise à jour devient maladroite.
  • Vous obtenez comme des limites artificielles parce que vous avez choisi un varchar (10) pour contenir votre liste séparée par des virgules.
  • et plus.

Donc, fondamentalement, ne faites pas ça.

Fondamentalement, vous supprimez le "relationnel" dans la "base de données relationnelle".

3
Pieter B

Il y a déjà beaucoup d'arguments pour que nous soyons déjà une mauvaise idée. Je pense qu'il serait juste d'ajouter quelques raisons pour lesquelles ce serait une bonne, ou du moins une bonne idée. Je ne sais pas combien de ceux-ci s'appliquent dans ce cas spécifique, mais il semble qu'au moins des remarques sur les performances effectuées soient pertinentes:

  • si le nombre et la longueur des chaînes sont strictement limités, la différence de performances doit être négligeable. Au moins pour certains cas Edge, les performances seront meilleures, car vous n'avez pas besoin de la jointure.
  • selon l'utilisation principale du champ, ce formulaire peut être plus facile à manipuler.
  • si la liste est ordonnée et que les données ne nécessitent pas de clés étrangères, les champs de liste sont bien supérieurs à ce que la base de données relationnelle peut fournir à cet égard.
  • le simple fait de s'appuyer sur un champ singulier existant peut être un choix prudent dans les systèmes où la migration de schéma est coûteuse. C'est certainement une dette technique, mais elle peut être du genre à valoir et à ne jamais rembourser, même si vous avez besoin de saigner de temps en temps.

Lors d'une tentative de refactoring, c'est toujours une bonne idée de comprendre d'abord la raison des choix de conception précédents. Assurez-vous que les conditions et les exigences ont en effet suffisamment changé pour garantir le coût et le risque.

0
Frax