web-dev-qa-db-fra.com

Utilisation d'une table de configuration Single Row dans la base de données SQL Server. Mauvaise idée?

Lors du développement d'une application de panier d'achat, j'ai constaté que je devais enregistrer les paramètres et les configurations en fonction des préférences et des exigences de l'administrateur. Ces informations peuvent être n'importe quoi: informations sur la société, identifiants de compte d'expédition, clés de l'API Paypal, préférences de notification, etc.

Il semble hautement inapproprié de créer une table pour stocker une seule ligne dans un système de base de données relationnelle.

Quelle est la manière appropriée de stocker cette information?

Remarque: mon SGBD est SQL Server 2008 et la couche de programmation est implémentée avec ASP.NET (en C #).

134
David Murdoch

Dans le passé, j'ai utilisé deux méthodes différentes: une table à une seule ligne et une table clé/paire de valeurs. Chaque approche présente des avantages et des inconvénients.

Rangée unique

  • positif: les valeurs sont stockées dans le type correct
  • positif: il est plus facile de traiter dans le code (à cause de ce qui précède)
  • positif: les valeurs par défaut peuvent être attribuées à chaque paramètre individuellement
  • négatif: un changement de schéma est nécessaire pour ajouter un nouveau paramètre
  • négatif: la table peut devenir très large s'il y a beaucoup de paramètres

Paire clé/valeur

  • positif: l'ajout de nouveaux paramètres ne nécessite pas de changement de schéma
  • positif: le schéma de la table est étroit, des lignes supplémentaires étant utilisées pour les nouveaux paramètres
  • négatif: chaque paramètre a la même valeur par défaut (null/empty?)
  • negatif: tout doit etre stocke sous forme de chaines de caracteres (ie. nvarchar)
  • négatif: lorsque vous utilisez les paramètres dans le code, vous devez savoir quel type est un paramètre et le lancer. 

L'option à une seule ligne est de loin la plus facile à utiliser. En effet, vous pouvez stocker chaque paramètre dans son type correct dans la base de données sans avoir à stocker les types des paramètres ainsi que leurs clés de recherche dans le code.

Une des choses qui me préoccupait avec l’utilisation de cette approche était d’avoir plusieurs lignes dans le tableau «spécial» des paramètres d’une seule ligne. J'ai surmonté cela par (dans SQL Server):

  • ajout d'une nouvelle colonne de bits avec une valeur par défaut de 0
  • création d'une contrainte de vérification pour s'assurer que cette colonne a la valeur 0
  • créer une contrainte unique sur la colonne de bits

Cela signifie qu'une seule ligne peut exister dans la table car la colonne de bits doit avoir la valeur 0, mais il ne peut y avoir qu'une seule ligne avec cette valeur en raison de la contrainte unique.

173
adrianbanks

Vous devez créer une table avec une colonne pour le type d'information et la valeur d'information (au moins). De cette manière, vous évitez de créer de nouvelles colonnes chaque fois qu'une nouvelle information est ajoutée.

10
Otávio Décio

Une seule rangée fonctionnera bien; il aura même des types forts:

show_borders    bit
admin_name      varchar(50)
max_users       int

Un inconvénient est que cela nécessite un changement de schéma (alter table) pour ajouter un nouveau paramètre. Une alternative est la normalisation, où vous vous retrouvez avec une table comme:

pref_name       varchar(50) primary key
pref_value      varchar(50) 

Cela a des types faibles (tout est un varchar), mais ajouter un nouveau paramètre consiste simplement à ajouter une ligne, ce que vous pouvez faire uniquement avec un accès en écriture à la base de données.

6
Andomar

Personnellement, je le stockerais sur une seule ligne si c'est ce qui fonctionne. Overkill pour le stocker dans une table SQL? probablement, mais il n’ya pas vraiment de mal à le faire.

4
E.J. Brennan

Comme vous l'avez deviné, et sauf dans les situations les plus simples, placer tous les paramètres de configuration dans une seule ligne présente de nombreux inconvénients. C'est une mauvaise idée...

Un moyen pratique de stocker des informations de configuration et/ou de type de préférence utilisateur est XML. De nombreux SGBD prennent en charge le type de données XML. La syntaxe XML vous permet de développer le "langage" et la structure décrivant la configuration à mesure que cette configuration évolue. L'un des avantages de XML est son support implicite pour la structure hiérarchique, permettant par exemple de stocker de petites listes de paramètres de configuration sans avoir à les nommer avec un suffixe numéroté. Un inconvénient possible du format XML est que la recherche et la modification générale de ces données ne sont pas aussi simples que d’autres approches (rien de compliqué, mais pas aussi simple/naturel)

Si vous souhaitez rester plus proche du modèle relationnel, vous avez probablement besoin du modèle Entity-Attribute-Value , les valeurs individuelles étant stockées dans une table ressemblant généralement à:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

AttributeId étant une clé étrangère vers une table dans laquelle chaque attribut possible ("paramètre de configuration" dans votre cas) est défini, avec

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

Enfin, EntityId vous permet d'identifier une entité qui "possède" ces différents attributs. Dans votre cas, il pourrait s'agir d'un identifiant utilisateur ou même simplement implicite si vous n'avez qu'une seule configuration à gérer.

En plus de permettre à la liste des paramètres de configuration possibles de s'allonger au fur et à mesure que l'application évolue, le modèle EAV place les "métadonnées", c'est-à-dire les données relatives à l'attribut elles-mêmes, dans des tables de données, évitant ainsi tout codage en dur des noms de colonnes couramment vus lorsque les paramètres de configuration sont stockés sur une seule ligne.

3
mjv

Vous n'avez certainement pas besoin de modifier votre schéma lorsque vous ajoutez un nouveau paramètre de configuration dans l'approche normalisée, mais vous modifiez probablement votre code pour traiter la nouvelle valeur. 

Ajouter une "table de modification" à votre déploiement ne semble pas être un énorme compromis pour la simplicité et la sécurité de type de l'approche à une seule ligne. 

3
Dave Mikesell

Une paire clé/valeur est similaire à un .Net App.Config qui peut stocker des paramètres de configuration.

Alors, quand vous voulez récupérer la valeur que vous pouvez faire:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';
2
rizalp1

Une méthode courante consiste à avoir une table "propriétés" semblable à un fichier de propriétés. Ici, vous pouvez stocker toutes les constantes de votre application, ou des choses pas si constantes que vous devez juste avoir autour.

Vous pouvez ensuite récupérer les informations de cette table selon vos besoins. De même, si vous avez d'autres paramètres à enregistrer, vous pouvez les ajouter. Voici un exemple:

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "Paypal_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "Paypal_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

De cette façon, vous pouvez stocker les données que vous avez et celles que vous aurez l'année prochaine et que vous ne connaissez pas encore :).

Dans cet exemple, votre portée et refId peuvent être utilisés pour tout ce que vous voulez sur le back-end. Donc, si le type de propriété "ADMIN" a une portée 0 réfId 2, vous savez de quelle préférence il s'agit.

Le type de propriété entre en jeu lorsqu'un jour, vous devez également stocker ici des informations non administratives.

Notez que vous ne devriez pas stocker les données du panier de cette façon, ni les recherches d’ailleurs. Cependant, si les données sont Système spécifique, alors vous pouvez certainement utiliser cette méthode.

Par exemple: si vous voulez stocker votre DATABASE_VERSION, vous utiliseriez une table comme celle-ci. Ainsi, lorsque vous aurez besoin de mettre à niveau l'application, vous pourrez consulter le tableau des propriétés pour connaître la version de votre logiciel dont dispose le client.

Le fait est que vous ne voulez pas utiliser ceci pour des choses qui se rapportent au panier. Conservez votre logique métier dans des tables relationnelles bien définies. Le tableau des propriétés est uniquement destiné aux informations système.

1
Stephano

Avoir une colonne clé comme varchar et une colonne valeur comme JSON. 1 est numérique alors que "1" est une chaîne. true et false sont tous deux booléens. Vous pouvez aussi avoir des objets.

0
kzh

Vous pouvez effectuer la paire clé/valeur sans conversions en ajoutant une colonne pour chaque type principal et une colonne vous indiquant la colonne dans laquelle se trouvent les données.

Donc, votre table ressemblerait à quelque chose comme:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

Il utilise un peu plus de place mais vous utilisez tout au plus quelques dizaines d'attributs. Vous pouvez utiliser une instruction case à partir de la valeur column_num pour extraire/joindre le champ de droite.

0
spintool

Je ne suis pas sûr qu'une seule ligne soit la meilleure implémentation pour la configuration. Il serait peut-être préférable d'avoir une ligne par élément de configuration avec deux colonnes (configName, configValue), bien que cela nécessite de transtyper toutes vos valeurs en chaînes et en retour.

Quoi qu'il en soit, il n'y a pas de mal à utiliser une seule ligne pour la configuration globale. Les autres options pour le stocker dans la base de données (variables globales) sont pires. Vous pouvez le contrôler en insérant votre première ligne de configuration, puis en désactivant les insertions sur la table pour empêcher plusieurs lignes.

0
sidereal

Désolé je viens comme, ans plus tard. Mais quoi qu'il en soit, ce que je fais est simple et efficace. Je crée simplement une table avec trois () colonnes:

ID - int (11)

nom - varchar (64)

valeur - texte

Ce que je fais avant de créer une nouvelle colonne de configuration, de la mettre à jour ou de lire, est de sérialiser la "valeur"! De cette façon, je suis sûr du type (bon, php est :))

Par exemple:

b: 0; est pourBOOLEAN (false)

b: 1; est pourBOOLEAN (true)

i: 1988; est pourINT

s: 5: "Kader"; est pour unSTRING d'une longueur de 5 caractères

J'espère que ça aide :)

0
Kader Bouyakoub