4 votes

Conception de bases de données avec des champs dynamiques : table unique ou nombreuses tables - nombreux index

Je dois choisir la structure d'une base de données qui stockera des types de contenu (par exemple, des articles de blog, des pages, des documents, des factures, des devis, etc.) avec des champs dynamiques : par exemple, les Estimate Le type de contenu doit comporter les champs title , date y total price .

Toutefois, dans le temps, ces champs peuvent être ajoutés ou supprimés, de sorte qu'après un an, l'image de l'entreprise sera modifiée. Estimate Le type de contant peut avoir le notes champ.

Il s'agit d'une tâche courante fournie par les CMS célèbres (drupal par exemple), mais je me demande quelle est la meilleure approche pour avoir les meilleures performances et la meilleure flexibilité : Drupal, par exemple, a l'habitude d'avoir une table avec les éléments suivants basic (par exemple title ), et tous les champs secondaires sont stockés dans des sous-tableaux créés à la volée et liés au tableau principal par des clés étrangères :

table node
| id | title         | ...
|  1 | First example |
table fields_node_total_price
| id | node_id | value  |
|  1 | 1       | 123.45 |
table fields_node_date
| id | node_id | value    |
|  1 | 1       | 12345677 |

etc.

Mon point de vue est que cette approche est très flexible, mais qu'elle peut facilement poser des problèmes de performance : pour obtenir tous les champs d'un document, vous devez joindre les tables plusieurs fois, et le code lui-même doit itérer plusieurs fois pour construire la requête (mais cela ne devrait pas être un problème).

Btw multi-table est l'approche la plus utilisée donc doit avoir de nombreux inconvénients.

Je pense aux désavantages de l'utilisation d'une seule table :

| id | title | total_price | date | ec...

J'ai fait quelques tests avec 5 et 50 champs supplémentaires ; les performances entre l'approche à table unique et l'approche à tables multiples sont énormes : la table unique est environ 50 fois plus rapide.

Chaque fois qu'un champ est ajouté, une colonne est ajoutée à la table Quels types de problèmes cette approche va-t-elle engendrer ?

EDITAR

Permettez-moi de vous donner quelques détails :

  1. L'application est encore en phase de conception, il s'agit d'une refonte complète d'une ancienne application où les numéros de champs étaient statiques.
  2. Nous avons fait quelques tests en simulant un objet à stocker, à la fois avec l'approche à table unique et l'approche à table multiple (en utilisant 50 champs), les résultats sont les suivants :

Temps en secondes :

Test                                                            1°          2°          3°          4°          5°          avg
1000 insert single_table                                        8,5687      8,6832      8,7143      8,7977      8,6906      8,69090137389466
1000 select single table LIKE '%key%' on char(250) field        1,5539      1,5540      1,5591      1,5602      1,5564      1,556705142
1000 select single table LIKE '%key%' on char(25) field         0,8848      0,8923      0,8894      0,8919      0,8888      0,889427996
1000 select single table id = $n                                0,2645      0,2620      0,2645      0,2632      0,2636      0,263564462
1000 select single table integer field < $j                     0,8627      0,8759      0,8673      0,8713      0,8767      0,870787334
1000 insert multi_table                                         446,3830    445,2843    440,8151    436,6051    446,0302    443,023531816
1000 select multi table LIKE '%key%' on char(250) field         1,7048      1,6822      1,6817      1,7041      1,6840      1,691367196
1000 select multi table LIKE '%key%' on char(25) field          0,9391      0,9365      0,9382      0,9431      0,9408      0,939536426
1000 select multi table id = $n                                 0,9336      0,9287      0,9349      0,9331      0,9428      0,93460784
1000 select multi table integer field < $j                      2,3366      2,3260      2,3134      2,3342      2,3228      2,326600456

5voto

Mr Moose Points 2264

Il peut être intéressant d'étudier ce qui est possible avec les bases de données NoSQL. Je ne les ai pas beaucoup utilisées moi-même, mais étant donné que vous dites que vous avez besoin de "...stocker des types de contenu (par exemple des articles de blog, des pages, des documents, des factures, des devis, etc.) avec des champs dynamiques", cela semble être une approche raisonnable.

Desde el Article de Wikipedia ;

...Ces magasins de données ne nécessitent pas nécessairement des schémas de table fixes, généralement éviter les opérations de jointure et s'étendent généralement à l'horizontale.

y

Les bases de données NoSQL sont souvent classées en fonction de la manière dont elles stockent les données. les données, et elles tombent dans des catégories telles que les magasins clé-valeur, les implémentations BigTable, Document-Store bases de données et Graph bases de données.

Je ne dis pas que c'est la réponse à tous vos problèmes, mais je dirais certainement que cela vaut la peine d'y jeter un œil.

En ce qui concerne les autres approches, j'ai utilisé par le passé la méthode Entité-Attribut-Valeur (EAV) et, bien que les performances soient probablement inférieures à celles d'un schéma fixe, j'estime qu'il s'agit d'un compromis qui permet de réduire les coûts. avait pour permettre la flexibilité du schéma.

Ma situation est probablement différente de la vôtre, mais je vais vous l'exposer au cas où cela vous serait utile. Nous avons décomposé la structure de la table en quelque chose de logique pour notre situation. Il y a une sorte de hiérarchie naturelle dans la mesure où il y a une table parente à laquelle la plupart des autres tables se rapportent.

Même si nous avions besoin d'une structure dynamique en raison de la variété des données que nous traitons, il y avait aussi une structure fixe. Par conséquent, pour chaque table nécessitant une structure dynamique, nous avons créé une table "principale" et une table "attributaire".

Un exemple de ceci (spécifique à SQL Server) peut être vu ci-dessous ;

CREATE TABLE [dbo].[ParentTbl](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [KnownCol1] [real] NOT NULL,
        -- Lots of other columns ommitted
    [KnownColn] [real] NULL
)        

CREATE TABLE [dbo].[MainTbl](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ParentId] [int] NOT NULL, -- FK to ParentTbl.Id
    [KnownCol1] [real] NOT NULL,
        -- Lots of other columns ommitted
    [KnownColn] [real] NULL
) 

CREATE TABLE [dbo].[MainTblAttr](
    [Id] [bigint] IDENTITY(1,1) NOT NULL, -- Note big int to cater for LOTS of records
    [MainId] [int] NOT NULL, --FK to MainTbl.Id
    [AttributeColumn] [nvarchar](255) NOT NULL,
    [AttributeValue] [nvarchar](max) NOT NULL
)

Vous pouvez ensuite effectuer une requête PIVOT pour vous aider à faire sortir vos données. Étant donné que vous aurez différents attributs, vous devez déterminer les colonnes à inclure dans le pivot. J'ai trouvé cet exemple est inestimable lorsque j'ai développé ma solution. Cependant, il existe de nombreux exemples sur SO. Il suffit de chercher "pivot dynamic columns".

Dans mon cas, le fait d'avoir une table parent est très utile pour limiter la quantité de données que je dois parcourir, car cela limite les enregistrements enfants que je dois examiner. Ce n'est peut-être pas le cas pour vous, mais j'espère que cela vous donnera quelques idées.

Bonne chance.

3voto

ARF Points 1345

Il n'y a pas de "bonne" réponse à cette question. Comme vous l'avez déjà mentionné, il s'agit de trouver un compromis entre flexibilité et rapidité.

Cela dépend de la nature du goulot d'étranglement dans votre application. Avez-vous effectué un profilage de votre application ? Le temps d'interrogation de la base de données est-il pertinent par rapport aux temps de ping de l'utilisateur final, à la vitesse de transfert, etc. Il est vraiment inutile de se préoccuper de l'optimisation des performances tant que vous n'êtes pas sûr d'avoir un problème de performances ET de savoir où se trouve le goulot d'étranglement !

J'aime utiliser firebug sur Firefox pour chronométrer le temps que met ma page à s'afficher auprès de l'utilisateur final et le comparer au résultat d'un chronomètre démarré avant la requête et arrêté après celle-ci. Pour plus de facilité, je l'imprime en bas de chaque page pendant le profilage.

Avez-vous envisagé des points de vue pour compenser les inconvénients de l'approche multi-tables ?

En ce qui concerne le problème des requêtes compliquées : avec les vues "virtuelles", vous pouvez éviter d'utiliser des jointures compliquées dans vos requêtes quotidiennes. Vous placez les jointures dans la définition de la vue et lorsque vous modifiez les champs dynamiques, il vous suffit d'ajuster la vue. (Note : avec les vues virtuelles, votre requête "simple" est réécrite dynamiquement en utilisant les jointures dans la définition de la vue).

En ce qui concerne le problème de vitesse, vous pouvez utiliser des définitions de vues "matérialisées" avec l'approche multi-table pour obtenir des performances de table unique. Avec les vues matérialisées, le SGBD crée une table physique à partir de la définition de la vue en utilisant les jointures dans la définition de la vue. Le résultat est que vous interrogez réellement une "table unique" - qui est cependant maintenue automatiquement en synchronisation avec votre définition multi-table. Vous obtenez le meilleur des deux mondes au détriment de l'espace de stockage de la BD.

En fonction de votre SGBD, vous pouvez également mettre à jour les vues directement (plutôt que les tables multiples). Je crois que c'est le cas avec MySQL. Avec Postgres, vous devez utiliser des déclencheurs pour indiquer au système comment modifier la table multiple sous-jacente.

En résumé :

  1. Personnellement, si je voulais créer un système qui dure, j'opterais pour l'approche multi-table avec des vues virtualisées. J'aurais alors Je ne "matérialiserais" que les vues pour lesquelles j'ai l'impression que les performances sont insuffisantes. manquent. Cela demande plus d'efforts pour démarrer à la vitesse d'une seule table, mais cela restera un atout. vitesse d'une seule table, mais il restera incroyablement flexible.
  2. Si je voulais quelque chose de rapide et sale mais rapide, j'opterais pour une table unique. - Mais il peut parfois être une douleur dans le mais d'incorporer certains des changements. Je ne vois pas de problème à avoir un grand nombre de colonnes. N'importe quel SGBD relationnel devrait faire l'affaire.
  3. Si je voulais quelque chose de rapide et sale mais flexible, j'opterais pour le multi-table et ne me soucierais pas de définir des vues et des déclencheurs, mais seulement de définir quelques index pour accélérer les opérations de jointure.

Dernier point : Vous devriez vraiment essayer de faire autant de traitement de données que possible dans le SGBD. (c'est-à-dire avec la requête) Vous avez déjà compris que "le code lui-même doit itérer de nombreuses fois pour construire la requête", ce qui est faux (voir vue, etc.). Cependant, cela suggère que vous avez tendance à faire trop de traitement de données dans votre application. Le langage SQL est incroyablement expressif et votre base de données utilisera très probablement des algorithmes bien plus efficaces pour évaluer votre traitement de données que tout ce que vous êtes susceptible d'implémenter vous-même. Remarque : une requête SQL qui semble incroyablement complexe peut en fait s'exécuter très rapidement !

Ainsi, si vous faites autre chose que simplement boucler le résultat de votre requête pour afficher une page Web, vous pouvez probablement intégrer davantage de logique dans votre requête.

0voto

remi bourgarel Points 3893

La première solution est une base de données "valeur-attribut" : Entité Attribut Valeur Base de données vs. modèle relationnel strict Ecommerce

J'opterais pour la dernière solution : les bases de données sont faites pour stocker des données et non des structures ! Nous avons un problème majeur car nous avons une base de données entité valeur attribut dans laquelle nous pouvons insérer n'importe quel type de données mais il est impossible de les interroger ou de cibler une donnée spécifique sans chaînes magiques.

Ou vous pouvez faire une autre solution : stocker votre champ additionnel dans une version sérialisée de votre objet AdditionnalFields.

0voto

mschneider Points 508

Dans les grands systèmes (50+ colonnes utilisant la réplication avec 5+ hôtes) la charge liée à la mise à jour d'une seule ligne dans une table augmente lorsque l'on ajoute des colonnes supplémentaires (parce que la ligne entière doit être répliquée). Cet effet peut être réduit en divisant une grande table en plusieurs parties. En utilisant des index appropriés, cela n'a pratiquement aucun coût pour les charges de travail analytiques. Bien que cela nuise aux performances des insertions.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X