2010-05-25 5 views
1

Je veux un schéma de base de données adaptable. Mais toujours utiliser une passerelle de données de table simple dans mon application, où je viens de passer un tableau $ data [] pour le stockage.
Les colonnes de base sont définies dans le schéma de table initial. Il y aura cependant quelques champs meta plus tard (ca 10-20). Je veux une certaine flexibilité là-bas et ne pas adapter la base de données manuellement chaque fois, ou -pauvre- changer la logique de l'application juste à cause de nouveaux champs.
Alors maintenant il y a deux options qui semblent fonctionnelles mais pas exagérées. Mais je ne suis pas sûr de l'évolutivité ou des inconvénients de la base de données.Conception de base de données extensible: automatique ALTER TABLE ou serialize() champ BLOB?

(1) automatique ALTER TABLE. Chaque fois que le tableau de données $ doit être enregistré, les clés sont comparées aux colonnes de la base de données en cours. Les nouvelles colonnes sont définies avant que les données $ ne soient insérées dans la table. semble en fait assez simple dans le code de test:

function save($data, $table="forum") { 
    // columns 
    if ($new_fields = array_diff(array_keys($data), known_fields($table))) { 
     extend_schema($table, $new_fields, $data); 
    } 
    // save 
    $columns = implode("`, `", array_keys($data)); 
    $qm = str_repeat(",?", count(array_keys($data)) - 1); 
    echo ("INSERT INTO `$table` (`$columns`) VALUES (?$qm);"); 

function known_fields($table) { 
    return unserialize(@file_get_contents("db:$table")) ?: array("id"); 

function extend_schema($table, $new_fields, $data) { 
    foreach ($new_fields as $field) { 
     echo("ALTER TABLE `$table` ADD COLUMN `$field` VARCHAR;"); 

Comme il est principalement méta champs d'information, en les ajoutant comme VARCHAR semble suffisante. Personne ne va interroger par eux de toute façon. Donc, la base de données est vraiment utilisée comme stockage ici.
Cependant, bien que je puisse vouloir ajouter beaucoup de nouveaux champs de données $ à la volée, ils ne seront pas toujours remplis.

(2) les champs sérialiser() en BLOB. Tout méta nouveau/externe peut être opaque à la base de données. Le simple tri des champs virtuels à partir des colonnes réelles de la base de données est simple. Et les champs meta peuvent simplement être serialize() d dans un champ blob/texte puis:

function ext_save($data, $table="forum") { 
    $db_fields = array("id", "content", "flags", "ext"); 
    // disjoin 
    foreach (array_diff(array_keys($data),$db_fields) as $key) { 
     $data["ext"][$key] = $data[$key]; 
     unset($data[$key]); 
    } 
    $data["ext"] = serialize($data["ext"]); 

Désérialisation et le déballage de cette colonne « ext » sur les requêtes de lecture est une surcharge mineure. L'avantage est qu'il n'y aura pas de colonnes peu remplies dans la base de données, donc je suppose que c'est plus compact et plus rapide que l'approche AUTO ALTER TABLE.
Bien sûr, cette méthode empêche d'utiliser l'un des nouveaux champs dans une clause WHERE ou GROUP BY. Mais je pense qu'aucun des méta-champs possibles (user_agent, author_ip, author_img, votes, hits, last_modified, ..) ne devrait/ne devrait jamais être utilisé de toute façon.

Donc, je préfère actuellement l'approche blob 'ext', même si c'est un billet aller simple.
Comment ces colonnes sont-elles appelées habituellement? (recherche d'exemples/doc)
Utilisez-vous la sérialisation XML pour les requêtes (très théorique) dans la base de données?

Le schéma de la table d'adaptation semble être une interface «plus propre», même si la plupart des colonnes peuvent rester vides. Comment cela affecte-t-il la vitesse? Combien de champs VARCHAR éparpillés peuvent-ils contenir MySQL/innodb?
Mais le plus important: existe-t-il une implémentation standard pour cela? Un pseudo ORM avec automatique Astuces ALTER TABLE? Stocker une simple liste de colonnes semble réalisable, mais quelque chose comme pdo :: getColumnMeta serait plus robuste.

Répondre

4

Parmi les deux idées que vous avez trouvées, j'irais pour la deuxième. Le premier me donne envie de pleurer, ne va pas avec.

Si vous êtes certain que vous n'aurez pas besoin d'interroger en fonction des champs Meta, alors la sérialisation est un moyen parfaitement valide pour les stocker.

Il existe également une troisième solution, plus préférable, que vous ne semblez pas avoir identifiée, à savoir utiliser un tableau croisé dynamique.Demandez à votre table d'origine, puis une seconde table avec un schéma comme:

metaid metaname metavalue 
1  colour  red 
2  texture rough 

Une troisième table « pivot » serait alors un lien entre les deux

tbl1_id metaid 
1   1 
2   2 

De cette façon, il n'y a pas de colonnes peu peuplées et vous conserver la possibilité d'interroger en fonction des métadonnées.

+0

J'ai * considéré * l'approche selfjoin-supertable. Utilisé quelque chose de similaire avant et lire quelques entrées connexes sur stackoverflow. Mais pour mon application actuelle, elle semblait trop lourde. C'est un concept plus propre du point de vue de la base de données, mais plus de surcharge pour l'interface et des ensembles de données trop confus. Donc, je vais probablement aller avec la méthode de sérialisation. A terminé la première approche. Parce qu'avec une base de données en croissance, un ALTER TABLE ne serait probablement plus aussi rapide. (Si moins de données devaient être anticipées, cela pourrait fonctionner, mais toujours bizarre.) – mario

Questions connexes