web-dev-qa-db-fra.com

Schéma de base de données dynamique

Quelle architecture est recommandée pour fournir du stockage pour un schéma de base de données logique dynamique?

Pour clarifier: lorsqu'un système doit fournir le stockage d'un modèle dont le schéma peut être étendu ou modifié par ses utilisateurs une fois en production, quelles sont les bonnes technologies, modèles de base de données ou moteurs de stockage qui permettront cela?

Quelques possibilités pour illustrer:

  • Création/modification d'objets de base de données via DML généré dynamiquement
  • Création de tables avec un grand nombre de colonnes physiques éparses et en utilisant uniquement celles requises pour le schéma logique "superposé"
  • Création d'un tableau "long et étroit" qui stocke les valeurs de colonnes dynamiques sous forme de lignes qui doivent ensuite être pivotées pour créer un ensemble de lignes "court et large" contenant toutes les valeurs d'une entité spécifique
  • Utilisation d'un système de type BigTable/SimpleDB PropertyBag

Toutes les réponses basées sur l'expérience du monde réel seraient grandement appréciées

65
Fake Jim

Ce que vous proposez n'est pas nouveau. Beaucoup de gens l'ont essayé ... la plupart ont constaté qu'ils recherchaient une flexibilité "infinie" et finissaient par beaucoup, beaucoup moins que cela. C'est le "roach motel" de la conception des bases de données - les données entrent, mais il est presque impossible de les sortir. Essayez de conceptualiser l'écriture du code pour TOUT type de contrainte et vous verrez ce que je veux dire.

Le résultat final est généralement un système BEAUCOUP plus difficile à déboguer, à entretenir et rempli de problèmes de cohérence des données. Ce n'est pas toujours le cas, mais le plus souvent, c'est comme ça que ça finit. Principalement parce que les programmeurs ne voient pas venir cette épave de train et ne parviennent pas à coder défensivement contre elle. De plus, cela finit souvent par montrer que la flexibilité "infinie" n'est vraiment pas nécessaire; c'est une très mauvaise "odeur" lorsque l'équipe de développement reçoit une spécification qui dit "Mon Dieu, je n'ai aucune idée du type de données qu'ils vont mettre ici, alors laissez-les mettre WHATEVER" ... et les utilisateurs finaux sont très bien avoir des types d'attributs prédéfinis qu'ils peuvent utiliser (codez un numéro de téléphone générique et laissez-les en créer - cela est trivial dans un système bien normalisé et maintient la flexibilité et l'intégrité!)

Si vous avez une très bonne équipe de développement et que vous êtes intimement conscient des problèmes que vous devrez surmonter avec cette conception, vous pouvez réussir à coder un puits conçu, pas terriblement buggy système. La plupart du temps.

Mais pourquoi commencer avec des chances si élevées contre vous?

Tu ne me crois pas? Google "One True Lookup Table" ou "conception de table unique". Quelques bons résultats: http://asktom.Oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10678084117056

http://thedailywtf.com/Comments/Tom_Kyte_on_The_Ultimate_Extensibility.aspx?pg=

http://www.dbazine.com/ofinterest/oi-articles/celko22

http://thedailywtf.com/Comments/The_Inner-Platform_Effect.aspx?pg=2

36
Matt Rogish

Un champ xml fortement typé dans MSSQL a fonctionné pour nous.

20
Bloodhound

Comme certains l'ont dit, ne faites cela que si vous n'avez pas d'autre choix. Un cas où cela est nécessaire est si vous vendez un produit standard qui doit permettre aux utilisateurs d'enregistrer des données personnalisées. Le produit de mon entreprise entre dans cette catégorie.

Si vous devez autoriser vos clients à le faire, voici quelques conseils:
- Créez un outil d'administration robuste pour effectuer les modifications de schéma et ne permettez pas que ces modifications soient effectuées d'une autre manière.
- Faites-en une fonction administrative; ne permettez pas aux utilisateurs normaux d'y accéder.
- Enregistrez chaque détail de chaque modification de schéma. Cela vous aidera à déboguer les problèmes et vous donnera également des données CYA si un client fait quelque chose de stupide.

Si vous pouvez faire ces choses avec succès (en particulier la première), alors l'une des architectures que vous avez mentionnées fonctionnera. Ma préférence est de modifier dynamiquement les objets de base de données, car cela vous permet de profiter des fonctionnalités de requête de votre SGBD lorsque vous accédez aux données stockées dans les champs personnalisés. Les trois autres options nécessitent que vous chargiez de gros morceaux de données, puis effectuiez la plupart de votre traitement de données en code.

16
Josh Yeager

J'ai une exigence similaire et j'ai décidé d'utiliser le schéma sans MongoDB .

MongoDB (de "humongous") est une base de données orientée document, open source, évolutive, haute performance, sans schéma écrite en langage de programmation C++. (Wikipédia)

Points forts:

  • a une fonctionnalité de requête riche (peut-être la plus proche des bases de données SQL)
  • prêt pour la production (foursquare, sourceforge l'utilise)

Lowdarks (choses que vous devez comprendre, afin que vous puissiez utiliser correctement mongo):

9
clyfe

Je l'ai fait dans un vrai projet:

La base de données se composait d'une table avec un champ qui était un tableau de 50. Il y avait un index 'Word' dessus. Toutes les données étaient sans type, donc l '"index Word" a fonctionné comme prévu. Les champs numériques étaient représentés sous forme de caractères et le tri réel avait été effectué côté client. (Il est toujours possible d'avoir plusieurs champs de tableau pour chaque type de données si nécessaire).

Le schéma de données logiques pour les tables logiques était contenu dans la même base de données avec des lignes de table de type différent (le premier élément du tableau). Il a également pris en charge la gestion des versions simple dans le style de copie sur écriture en utilisant le même champ "type".

Avantages:

  1. Vous pouvez réorganiser et ajouter/supprimer vos colonnes dynamiquement, pas besoin de vidage/rechargement de la base de données. Toute nouvelle donnée de colonne peut être définie (virtuellement) sur sa valeur initiale en un temps nul.
  2. La fragmentation est minime, car tous les enregistrements et les tables sont de la même taille, ce qui donne parfois de meilleures performances.
  3. Tout le schéma de table est virtuel. Toute structure de schéma logique est possible (même récursive ou orientée objet).
  4. Il est bon pour les données "à écriture unique, à lecture seule, sans suppression/marquer comme supprimées" (la plupart des applications Web sont en fait comme ça).

Désavantages:

  1. Indexation uniquement par mots entiers, pas d'abréviation,
  2. Des requêtes complexes sont possibles, mais avec une légère dégradation des performances.
  3. Dépend si votre système de base de données préféré prend en charge les tableaux et les index Word (il a été mis en œuvre dans PROGRESS RDBMS).
  4. Le modèle relationnel est uniquement dans l'esprit du programmeur (c'est-à-dire uniquement au moment de l'exécution).

Et maintenant, je pense que la prochaine étape pourrait être de mettre en œuvre une telle base de données au niveau du système de fichiers. Cela pourrait être relativement facile.

7
Thevs

L'intérêt d'avoir une base de données relationnelle est de garder vos données en sécurité et cohérentes. Dès que vous autorisez les utilisateurs à modifier le schéma, votre intégrité des données s'en va ...

Si votre besoin est de stocker des données hétérogènes, par exemple comme un scénario CMS, je suggérerais de stocker du XML validé par un XSD dans une rangée. Bien sûr, vous perdez les performances et les capacités de recherche faciles, mais c'est un bon compromis à mon humble avis.

Depuis 2016, oubliez XML! Utilisez JSON pour stocker le sac de données non relationnel, avec une colonne correctement typée comme backend. Vous ne devriez normalement pas avoir besoin d'interroger par valeur à l'intérieur du sac, ce qui sera lent même si de nombreuses bases de données SQL contemporaines comprennent nativement JSON.

6
Sklivvz

Créer 2 bases de données

  • DB1 contient des tables statiques et représente l'état "réel" des données.
  • DB2 est libre pour les utilisateurs de faire comme ils le souhaitent - ils (ou vous) devrez écrire du code pour remplir leurs tables de forme étrange à partir de DB1.
3
AJ.

Pour moi, ce que vous voulez vraiment, c'est une sorte de "méta-schéma", un schéma de base de données qui est capable de décrire un schéma flexible pour stocker les données réelles. Les modifications de schéma dynamiques sont délicates et ne sont pas quelque chose avec quoi vous voulez jouer, surtout pas si les utilisateurs sont autorisés à effectuer la modification.

Vous n'allez pas trouver une base de données plus adaptée à cette tâche que toute autre, donc votre meilleur pari est simplement d'en sélectionner une en fonction d'autres critères. Par exemple, quelle plateforme utilisez-vous pour héberger la base de données? Dans quelle langue l'application est-elle écrite? etc

Pour clarifier ce que je veux dire par "méta-schéma":

CREATE TABLE data (
    id INTEGER NOT NULL AUTO_INCREMENT,
    key VARCHAR(255),
    data TEXT,

    PRIMARY KEY (id)
);

Il s'agit d'un exemple très simple, vous auriez probablement quelque chose de plus spécifique à vos besoins (et, espérons-le, un peu plus facile à travailler), mais il sert à illustrer mon propos. Vous devez considérer que le schéma de la base de données lui-même est immuable au niveau de l'application; tout changement structurel doit se refléter dans les données (c'est-à-dire l'instanciation de ce schéma).

3
Daniel Spiewak

Je sais que les modèles indiqués dans la question sont utilisés partout dans les systèmes de production. Un assez grand est utilisé dans une grande université/institution d'enseignement pour laquelle je travaille. Ils utilisent spécifiquement l'approche de table longue et étroite pour cartographier les données recueillies par de nombreux systèmes d'acquisition de données variés.

En outre, Google a récemment publié son protocole de partage de données interne, tampon de protocole, en tant qu'open source via son site de code. Un système de base de données calqué sur cette approche serait très intéressant.

Vérifiez les points suivants:

modèle entité-valeur-attribut

Tampon de protocole Google

3
siculars

Je pense que l'approche EAV est la meilleure approche, mais elle a un coût élevé

2
kamal

Wikipedia a une excellente vue d'ensemble de l'espace problématique:

http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model

2
DenNukem

Je sais que c'est un vieux sujet, mais je suppose qu'il ne perd jamais de son actualité. Je développe quelque chose comme ça en ce moment. Voici mon approche. J'utilise un paramètre de serveur avec MySQL, Apache, PHP et Zend Framework 2 comme cadre d'application, mais cela devrait fonctionner aussi bien avec tout autre paramètre.

Voici un guide d'implémentation simple, vous pouvez le faire évoluer vous-même plus loin.

Vous devrez implémenter votre propre interpréteur de langage de requête, car le SQL efficace serait trop compliqué.

Exemple:

select id, password from user where email_address = "[email protected]"

La disposition physique de la base de données:

'Spécifications' du tableau: (doit être mis en cache dans votre couche d'accès aux données)

  • id: int
  • parent_id: int
  • nom: varchar (255)

'Articles' du tableau:

  • id: int
  • parent_id: int
  • spec_id: int
  • données: varchar (20000)

Contenu des "spécifications" du tableau:

  • 1, 0, "utilisateur"
  • 2, 1, 'email_address'
  • 3, 1, "mot de passe"

Contenu des éléments du tableau:

La traduction de l'exemple dans notre propre langage de requête:

select id, password from user where email_address = "[email protected]"

à SQL standard ressemblerait à ceci:

select 
    parent_id, -- user id
    data -- password
from 
    items 
where 
    spec_id = 3 -- make sure this is a 'password' item
    and 
    parent_id in 
    ( -- get the 'user' item to which this 'password' item belongs
        select 
            id 
        from 
            items 
        where 
            spec_id = 1 -- make sure this is a 'user' item
            and 
            id in 
            ( -- fetch all item id's with the desired 'email_address' child item
                select 
                    parent_id -- id of the parent item of the 'email_address' item
                from 
                    items 
                where 
                    spec_id = 2 -- make sure this is a 'email_address' item
                    and
                    data = "[email protected]" -- with the desired data value
            )
    )

Vous devrez avoir le tableau des spécifications mis en cache dans un tableau associatif ou une table de hachage ou quelque chose de similaire pour obtenir les spec_id à partir des noms de spécifications. Sinon, vous devrez insérer un peu plus de surcharge SQL pour obtenir le spec_id à partir des noms, comme dans cet extrait:

Mauvais exemple, ne l'utilisez pas, évitez cela, cachez plutôt le tableau des spécifications!

select 
    parent_id, 
    data 
from 
    items 
where 
    spec_id = (select id from specs where name = "password") 
    and 
    parent_id in (
        select 
            id 
        from 
            items 
        where 
            spec_id = (select id from specs where name = "user") 
            and 
            id in (
                select 
                    parent_id 
                from 
                    items 
                where 
                    spec_id = (select id from specs where name = "email_address") 
                    and 
                    data = "[email protected]"
            )
    )

J'espère que vous comprenez l'idée et pouvez déterminer par vous-même si cette approche est réalisable pour vous.

Prendre plaisir! :-)

2
Oliver Konig

Dans le passé, j'ai choisi l'option C - Création d'un tableau "long et étroit" qui stocke les valeurs de colonnes dynamiques sous forme de lignes qui doivent ensuite être pivotées pour créer un ensemble de lignes "court et large" contenant toutes les valeurs d'une entité spécifique.. Cependant, j'utilisais un ORM, et cela rendait vraiment les choses douloureuses. Je ne peux pas penser à la façon dont vous le feriez dans, disons, LinqToSql. Je suppose que je devrais créer une table de hachage pour référencer les champs.

@Skliwz: Je suppose qu'il est plus intéressé à autoriser les utilisateurs à créer des champs définis par l'utilisateur.

0
Danimal

Sur le wiki c2.com, l'idée de "Dynamic Relational" a été explorée. Vous N'AVEZ PAS besoin d'un DBA: les colonnes et les tables sont en création sur écriture, sauf si vous commencez à ajouter des contraintes pour le faire agir plus comme un SGBDR traditionnel: à mesure qu'un projet arrive à maturité, vous pouvez le "verrouiller" de manière incrémentielle.

Conceptuellement, vous pouvez considérer chaque ligne comme une instruction XML. Par exemple, un enregistrement d'employé peut être représenté comme suit:

<employee lastname="Li" firstname="Joe" salary="120000" id="318"/>

Cela n'implique pas qu'il doit être implémenté en XML, c'est juste une conceptualisation pratique. Si vous demandez une colonne non existante, telle que "SELECT madeUpColumn ...", elle est traitée comme vide ou nulle (sauf si des contraintes supplémentaires l'interdisent). Et il est possible d'utiliser SQL , bien qu'il faille faire attention aux comparaisons en raison du modèle de type implicite. Mais à part la gestion des types, les utilisateurs d'un système relationnel dynamique se sentiraient comme chez eux car ils peuvent tirer parti de la plupart de leurs connaissances existantes en SGBDR. Maintenant, si quelqu'un voulait simplement le construire ...

0
FloverOwe

ElasticSearch. Vous devez en tenir compte en particulier si vous traitez avec des ensembles de données que vous pouvez partitionner par date, vous pouvez utiliser JSON pour vos données et ne sont pas déterminés à utiliser SQL pour récupérer les données.

ES déduit votre schéma pour tout nouveau champ JSON que vous envoyez, soit automatiquement, avec des astuces, soit manuellement que vous pouvez définir/modifier par une seule commande HTTP ("mappages"). Bien qu'il ne prenne pas en charge SQL, il possède de grandes capacités de recherche et même des agrégations.

0
Oren