web-dev-qa-db-fra.com

Données de configuration: table à une seule ligne vs table de paires nom-valeur

Disons que vous écrivez une application qui peut être configurée par l'utilisateur. Pour stocker ces "données de configuration" dans une base de données, deux modèles sont couramment utilisés.

  1. table à une seule ligne

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. La table paire nom-valeur

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

J'ai vu les deux options dans la nature, et les deux ont des avantages et des inconvénients évidents, par exemple:

  • Les tableaux à une ligne limitent le nombre d'options de configuration que vous pouvez avoir (car le nombre de colonnes dans une ligne est généralement limité). Chaque option de configuration supplémentaire nécessite une modification du schéma de base de données.
  • Dans une table nom-valeur-paire, tout est "typé en chaîne" (vous devez encoder/décoder vos paramètres booléens/date/etc.).
  • (beaucoup plus)

Y a-t-il un consensus au sein de la communauté du développement sur quelle option est préférable?

65
Heinzi

Personnellement, je préfère les tables à une rangée pour la plupart des choses. S'il est vrai qu'il est moins flexible, sauf si vous vous attendez à un comportement dynamique, il est parfaitement acceptable d'ajouter des colonnes supplémentaires plus tard si vous en avez besoin. D'une certaine manière, c'est l'équivalent d'utiliser un dictionnaire/carte pour contenir des paires nom-valeur par rapport à avoir des membres de classe lors de la programmation. Certes, ce n'est pas une métaphore parfaite, mais de nombreux avantages et inconvénients sont mis en parallèle lorsque vous y pensez.

Alors, utiliseriez-vous un dictionnaire/une carte sur les membres de la classe? Probablement pas sauf si vous aviez des raisons de penser que la quantité de données à représenter est entièrement adaptable, un peu comme avoir une table de paires nom-valeur.

16
Neil

J'irais généralement avec l'option 2 MAIS j'aurais plusieurs colonnes pour appliquer le type de données

ConfigOption   |   textValue    |   DateValue   |   NumericValue

L'option 1 présente l'avantage supplémentaire que vous pouvez très facilement "échanger" des configurations entières en ajoutant une colonne Active.

12
Morons

Pour moi, que vous optiez pour une seule rangée ou EAV dépend de la façon dont vous souhaitez les consommer.

La puissance de l'EAV est que de nouvelles données peuvent être ajoutées sans changement de structure. Cela signifie que si vous voulez une nouvelle valeur de configuration, il vous suffit de l'ajouter à la table et de la retirer où vous le souhaitez dans le code, et vous n'avez pas besoin d'ajouter un nouveau champ au domaine, schéma, mappage, requêtes DAL , etc.

Son défaut est qu'il n'a que la structure la plus simple, ce qui vous oblige à traiter les données avec pessimisme. Chaque utilisation d'une valeur de configuration doit s'attendre à ce que la valeur ne soit pas présente, ou pas au format approprié, et se comporte en conséquence lorsqu'elle ne l'est pas. Une valeur de configuration peut ne pas être analysable en double, en entier ou en char. Il peut être nul. il peut n'y avoir aucune ligne pour la valeur. Les moyens de contourner cela nécessitent généralement qu'une seule valeur "par défaut" valide existe pour toutes les valeurs de configuration d'un type particulier dans le code (extrêmement rare; le plus souvent, la valeur par défaut est tout aussi problématique pour la consommation de code que aucun) ou pour conserver un dictionnaire codé en dur des valeurs par défaut (qui doit changer chaque fois qu'une nouvelle colonne est ajoutée, ce qui rend le principal avantage du stockage EAV assez théorique).

Une seule rangée large est à peu près le contraire. Vous le mappez à une seule instance d'un objet Configuration avec un champ/propriété pour chaque valeur de configuration existante. Vous savez exactement quel type ces valeurs doivent être au moment de la compilation, et vous "échouez rapidement" dans le DAL si une colonne de configuration n'existe pas ou n'a pas une valeur du type approprié, vous donnant un endroit pour intercepter les exceptions basées sur les problèmes de récupération/hydratation de la configuration.

Le principal inconvénient est qu'un changement structurel est nécessaire pour chaque nouvelle valeur; nouvelle colonne DB, nouvelle colonne dans le DAL (soit le mappage ou les requêtes/SP SQL), nouvelle colonne de domaine, tout cela est nécessaire pour tester correctement l'utilisation.

La situation appropriée dans laquelle utiliser l'un ou l'autre de ces éléments est la situation dans laquelle les inconvénients sont atténués. Pour moi, la plupart des situations de codage de configuration nécessitent une implémentation sur une seule ligne. C'est principalement parce que si vous introduisez une toute nouvelle valeur de configuration qui régit le comportement d'une partie de votre programme, vous devez déjà changer le code en tiliser la nouvelle valeur de configuration; pourquoi ne pas passer à l'objet config et ajouter la valeur à utiliser?

En bref, un schéma EAV pour stocker la configuration ne résout pas vraiment le problème qu'il prétend résoudre, et la plupart des solutions aux problèmes qu'il présente violent DRY.

8
KeithS

Plus précisément pour les valeurs de configuration, je dirais - aller avec la seule ligne. À moins que vous ne soyez actuellement en phase de développement, à quelle fréquence ces colonnes vont-elles changer de toute façon?

Il est probablement préférable de sécuriser le type de données de values, plutôt que de coder pour l'extensibilité que vous n'êtes pas susceptible d'avoir dans le temps d'arrêt entre les grandes versions (r). En outre, l'ajout ou la suppression d'une seule colonne est à peu près la migration la plus simple qui soit. Je ne prévois pas de maux de tête lors de la création d'une nouvelle option de configuration.

De plus, vous avez dit que les "utilisateurs" peuvent configurer ces options sans donner de plafond. S'agit-il de configurations par utilisateur? Si c'est le cas, je soutiendrai encore plus fortement que les options de configuration devraient être dans les colonnes - une seule ligne par utilisateur. Cela permettra d'économiser beaucoup de maux de tête de maintenance plus tard.

3
Izkata

Si vos clients peuvent traiter des fragments JSON (c'est-à-dire non seulement des tableaux et des dictionnaires, mais aussi des chaînes simples, des nombres, des booléens, des valeurs nulles), vous pouvez avoir une table à plusieurs lignes avec le nom de l'option et une valeur de chaîne contenant JSON. Cela vous permet également de stocker des valeurs structurées, et le code de traitement de celles-ci devrait déjà être là.

Si vos clients ne peuvent pas traiter les fragments JSON, obtenez de nouveaux clients.

2
gnasher729

Avantages d'une seule ligne: bien définis. Inconvénients: la modification de la configuration peut être pénible. Migrations de bases de données, etc.

Avantages Entity-Value: Super flexible, prend en charge l'évolution de votre configuration. Inconvénients: intégrité référentielle? Plus de contrôles dans votre code pour voir si la propriété existe avant de pouvoir y faire quoi que ce soit.

Je prendrais l'approche 2 soutenue par une base de données non relationnelle comme Mongo. S'il y a quelque chose dont vous pouvez être sûr, son changement.

1
JVXR

Utilise les deux!

Triez quelles options peuvent avoir plusieurs instances et quelles options sont génériques.

La table à une seule ligne (configurations)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

La table nom-valeur-paire (options)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

Je pense que c'est plus flexible.

1
Andrew Luca