2010-10-25 9 views
22

Je me demandais si vous avez un site Web avec une douzaine de différents types d'annonces (boutiques, restaurants, clubs, hôtels, événements) qui nécessitent des champs différents, y at-il un avantage de créer une table avec des colonnes définies comme si
Exemple Shop:table fixe unique avec plusieurs colonnes vs tables abstraites flexibles

shop_id | name | X | Y | city | district | area | metro | station | address | phone | email | website | opening_hours 

Ou une approche plus abstraite semblable à ceci:

object_id | name   
--------------- 
1   | Messy Joe's 
2   | Bate's Motel 

type_id | name 
--------------- 
1  | hotel 
2  | restaurant 


object_id | type_id 
--------------- 
1   | 2 
2   | 1 

field_id | name   | field_type 
--------------- 
1  | address  | text 
2  | opening_hours | date 
3  | speciality  | text 

type_id | field_id 
--------------- 
1  | 1 
1  | 2 
2  | 1 
2  | 3 

object_id | field_id | value 
1   | 1  | 1st street.... 
1   | 3  | English Cuisine 

Bien sûr, il peut être plus abstraite si la valeur de sont prédéfinies (exemple: spécialités coul Si j'ai l'approche abstraite, cela peut être très flexible, mais les requêtes seront plus complexes avec beaucoup de jointures. Mais je ne sais pas si cela affecte la performance, en exécutant ces requêtes 'plus complexes'.

Je serais intéressé de savoir quels sont les avantages et les inconvénients des deux méthodes. Je peux juste imaginer pour moi-même, mais je n'ai pas l'expérience pour le confirmer.

+2

Merci. Vous pouvez être intéressé par ** cette [question/réponse] (http://stackoverflow.com/questions/4304217/database-schema-which-can-support-specialized-properties/4359193#4359193) ** ainsi. – PerformanceDBA

Répondre

71

Certaines questions doivent être clarifiées et résolues avant nous pouvons entrer dans une discussion raisonnable.

Résolution Pré-requis

  1. étiquettes
    Dans une profession qui exige une précision, il est important que nous utilisons des étiquettes précises, pour éviter toute confusion, et pour que nous puissions communiquer sans avoir à utiliser descriptions et qualificatifs de longue haleine.
    .
    Ce que vous avez publié en tant que tables fixes, est non normalisé. Assez, il peut s'agir d'une tentative à la troisième forme normale, mais en fait il s'agit d'un fichier plat, non normalisé (non dénormalisé.) Ce que vous avez publié comme AbstractTables est, pour être précis, Entity-Attribute-Value, qui est presque, mais pas tout à fait, sixième forme normale, et est donc plus normalisée que 3NF. en supposant qu'il est fait correctement, bien sûr.

    • Le fichier plat dénormalisé est pas « dénormalisé ». il est plein à craquer de la duplication (rien n'a été fait pour supprimer les groupes répétitifs et les colonnes dupliquées ou pour résoudre les dépendances) et les Nulls, il s'agit d'un porc de performance de plusieurs façons, et empêche la simultanéité

    • Afin d'être Denormlaised, il doit d'abord être normalisé, puis la normalisation reculer un peu pour une bonne raison. Comme il n'est pas normalisé en premier lieu, il ne peut pas être dénormalisé. C'est simplement non normalisé.

    • On ne peut pas dire qu'il soit dénormalisé "pour la performance", car étant un porc de performance, c'est l'antithèse de la performance. Eh bien, ils ont besoin d'une justification pour le manque de conception formelle], et "pour la performance" est-il. Même le plus petit examen formel a révélé la fausse déclaration (mais très peu de gens peuvent fournir, de sorte qu'il reste caché, jusqu'à ce qu'ils obtiennent un étranger à aborder, vous l'aurez deviné, le problème de performance massive).

    • Les structures normalisées fonctionnent beaucoup mieux que les structures non normalisées. Les structures plus normalisées (EAV/6NF) fonctionnent mieux que les structures moins normalisées (3NF/5NF).

    • Je suis d'accord avec l'idée maîtresse de OMG Ponies, mais pas leurs étiquettes et définitions

    • plutôt que de dire « ne pas « denormalise » à moins que vous devez », je dis, « Normaliser fidèlement, période ' et ' s'il y a un problème de performance, vous n'avez pas normalisé correctement '.
      .
  2. Wiki
    Les entrées ré formes normales et sont une blague Normalization complète. Plus précisément, les définitions sont incorrectes; ils confondent les formes normales; ils n'ont aucune idée du processus de normalisation; et ils accordent le même poids à des FN absurdes ou douteuses qui ont été démystifiées depuis longtemps. Le résultat est, Wiki ajoute à un sujet déjà confus et rarement compris. Alors ne perds pas ton temps.
    .
    Cependant, pour progresser, sans que cette référence ne soit un obstacle, permettez-moi de dire ceci.

    • La définition de 3NF est stable et n'a pas changé.
    • Il y a beaucoup de confusion des FN entre 3NF et 5NF. La vérité est que c'est un domaine qui a progressé au cours des 15 dernières années; et de nombreux orgs, universitaires ainsi que des fournisseurs avec leurs produits avec des limitations, ont sauté pour créer une nouvelle "forme normale" pour valider leurs offres. Tous servant intérêts commerciaux et académiquement malsain. 3NF dans son état original non échantillonné a prévu et garanti certains attributs.
    • La somme totale est, 5NF est aujourd'hui, ce que 3NF devait être il y a 15 ans, et vous pouvez sauter les plaisanteries commerciales et la douzaine de NF "spéciales" (commerciales et pseudo-académiques) entre les deux, certains dont sont identifiés dans Wiki, et même dans des termes confus.
      .
  3. Puisque vous avez été en mesure de comprendre et d'implémenter l'EAV dans votre message, vous n'aurez aucun problème à comprendre ce qui suit. Bien sûr, un vrai modèle relationnel est des clés pré-requis, forts, etc. Cinquième normale forme est, puisque nous sautons la quatrième:

    • Troisième normale Forme
      • qui termes simples et définitives est, chaque colonne non-clé dans chaque table a 1 :: 1 relation avec la clé primaire de la table,
      • et pas d'autres colonnes non-clés
    • duplication des données zéro (le résultat, si la normalisation est dilige progressé ntly; pas atteint par l'intelligence ou l'expérience seule, ou en travaillant vers lui comme un objectif sans le processus formel)
    • aucune Anomalies de mise à jour (lorsque vous mettez à jour une colonne quelque part, vous ne devez pas mettre à jour la même colonne située ailleurs, la colonne existe en un et un seul endroit).
      .
  4. Sixième normale Forme est le cinquième cours normal forme, plus:

    • Élimination des données manquantes (colonnes). C'est la seule vraie solution au problème nul (aussi appelé Handling Missing Values), et le résultat est une base de données sans Nulls. (Cela peut être fait à 5NF avec des standards et des substituts Null mais ce n'est pas optimal.) Comment interpréter et afficher les valeurs manquantes est une autre histoire.
      .
  5. EAV vs sixième normale Forme
    Toutes les bases de données que j'ai écrit, sauf un, sont purs 5NF. J'ai travaillé avec (administré, réparé, amélioré) quelques bases de données EAV, et j'ai implémenté une vraie base de données 6NF. EAV est une implémentation lâche de 6NF, souvent réalisée par des personnes qui ne maîtrisent pas la Normalisation et les FN, mais qui peuvent voir la valeur et avoir besoin de la flexibilité de EAV. Vous êtes un parfait exemple. La différence est la suivante: parce qu'elle est lâche, et parce que les implémenteurs n'ont pas de référence (6NF) à laquelle ils doivent être fidèles, ils implémentent seulement ce dont ils ont besoin, et ils l'écrivent tous dans le code; cela finit par être un modèle incohérent.
    .
    Considérant que, une mise en œuvre pure 6NF a un point de référence académique pur, et donc il est généralement plus serré et cohérent. Généralement, cela apparaît dans deux éléments visibles:
    • 6NF possède un catalogue pour contenir des métadonnées, et tout est défini dans les métadonnées, pas dans le code. EAV n'en a pas, tout est dans le code (les exécutants gardent la trace des objets et des attributs). Évidemment, un catalogue facilite l'ajout de colonnes, la navigation, et permet aux utilitaires d'être formés.
    • 6NF, lorsqu'il est compris, fournit la véritable solution au problème nul. Les implémenteurs d'EAV, puisqu'ils sont absents du contexte 6NF, gèrent les données manquantes dans le code, de façon incohérente ou pire, autorisent les Nulls dans la base de données. Les implémenteurs de 6NF interdisent les Nulls, et gèrent les Données manquantes de façon cohérente et élégante, sans avoir besoin de constructions de code (pour la gestion Null, il faut bien sûr coder les données manquantes bien sûr).
      .
      Par exemple. Pour les bases de données 6NF avec un catalogue, j'ai un ensemble de procs qui généreront le SQL nécessaire pour effectuer tous les SELECT et fournir des vues dans 5NF pour tous les utilisateurs, donc ils n'ont pas besoin de connaître ou de comprendre la structure 6NF sous-jacente . Ils sont chassés du catalogue. Ainsi, les changements sont faciles et automatisés. Les types EAV le font manuellement, en raison de l'absence du catalogue.

Maintenant, nous pouvons commencer la

Discussion

« Bien sûr, il peut être plus abstraite si valeur de sont prédéfinies (exemple: spécialités pourraient avoir leur liste ) "

Bien sûr. Mais ne soyez pas trop "abstrait". Maintenez la cohérence et implémentez ces listes de la même manière EAV (ou 6NF) que les autres listes.

« Si je prends l'approche abstraite qu'il peut être très flexible, mais les requêtes sera plus complexe avec beaucoup de jointures. Mais je ne sais pas si cela affecte les performances , l'exécution de ces 'plus complexe' requêtes. "

  1. Les relations sont de piétons dans les bases de données relationnelles. Le problème n'est pas la base de données, le problème est que SQL est lourd lors de la gestion des jointures, en particulier les clés composées.
  2. Les bases de données EAV et 6NF ont plus de Joins, ce qui est aussi piéton, ni plus ni moins. Si vous devez coder chaque SELECT manuellement, bien sûr, la lourdeur devient vraiment lourde.
  3. L'ensemble du problème peut être éliminé en (a) en passant par 6NF sur EAV et (b) en implémentant un catalogue, à partir duquel vous pouvez (c) générer tout le SQL de base. Élimine également toute une classe d'erreurs.
  4. C'est un mythe commun que les jointures ont un coût. Totalement faux. La jointure est implémentée au moment de la compilation, il n'y a rien de substantiel pour les cycles CPU 'cost'. Le problème est la taille des tables jointes, pas le coût de la jointure entre ces mêmes tables.Rejoindre deux tables avec des millions de lignes chacune, sur une relation PK⇢FK correcte, chacune ayant les indices appropriés (Unique du côté parent [FK]; Unique du côté Enfant) est instantanée; ; où l'index enfant n'est pas unique, mais au moins la colonne principale est valide, elle est plus lente; où il n'y a pas d'index utile, bien sûr c'est très lent. Rien de tout cela n'a à voir avec le coût de Join. Lorsque plusieurs lignes sont renvoyées, le goulot d'étranglement sera le réseau et la disposition du disque; pas le traitement de la jointure.
  5. Par conséquent, vous pouvez obtenir aussi "complexe" que vous le souhaitez, il n'y a pas de coût, SQL peut le gérer.

Je serais curieux de savoir quels sont les et inconvénients des deux méthodes. Je peux juste imaginer pour moi-même, mais je n'ai pas l'expérience pour confirmer cela.

  1. 5NF (ou 3NF pour ceux qui ne l'ont pas fait la progression) est le plus facile et mieux, en termes de mise en œuvre, la facilité d'utilisation (les développeurs ainsi que les utilisateurs), l'entretien. L'inconvénient est, chaque fois que vous ajoutez une colonne, vous devez modifier la structure de la base de données (table DDL). C'est bien quelques cas, mais pas dans la plupart des cas, en raison du changement de contrôle en place, assez onéreux. Deuxièmement, vous devez changer le code existant (le code manipulant la nouvelle colonne ne compte pas, parce que c'est un impératif): là où de bonnes normes sont implémentées, cela est minimisé; en cas d'absence, la portée est imprévisible. EAV (qui est ce que vous avez posté), permet d'ajouter des colonnes sans changements DDL. C'est la seule raison pour laquelle les gens le choisissent. (le code traitant la nouvelle colonne ne compte pas, parce que c'est un impératif). S'il est bien implémenté, cela n'affectera pas le code existant; sinon, ce sera le cas. Mais vous avez besoin de développeurs compatibles EAV. Quand EAV est mal implémenté, c'est abominable, un désordre pire que 5NF mal fait, mais pas pire que Unnormalised qui est ce que la plupart des bases de données sont (dénaturé comme "dénormalisé pour la performance"). bien sûr, il est encore plus important (que dans 5NF/3NF) de posséder un contexte Transaction fort, car les colonnes sont beaucoup plus distribuées. De même, il est essentiel de conserver l'intégrité référentielle déclarative: les désordres que j'ai vus étaient dus en grande partie aux développeurs supprimant DRI parce qu'il devenait "trop ​​difficile à maintenir", le résultat était, comme vous pouvez l'imaginer, une mère de données tas avec des lignes et des colonnes 3NF/5NF en double partout. Et la gestion de Null incohérent.

  2. Il n'y a pas de différence de performance, en supposant que le serveur a été raisonnablement configuré pour l'usage prévu. (Ok, il y a des optimisations spécifiques qui ne sont possibles qu'en 6NF, ce qui n'est pas possible dans d'autres FN, mais je pense que cela sort du cadre de ce fil.) Et encore, l'EAV mal fait peut causer des goulets d'étranglement inutiles. Non normalisé.

  3. Bien sûr, si vous allez avec EAV, je recommande plus de formalité; acheter le quid complet; aller avec 6NF; implémenter un catalogue; utilitaires pour produire du SQL; Vues gérer les données manquantes de manière cohérente; éliminer complètement les Nuls. Cela réduit votre vulnérabilité à la qualité de vos développeurs; ils peuvent oublier les problèmes ésotériques EAV/6NF, utiliser les vues et se concentrer sur la logique de l'application.

Pardonnez le poste long.

+4

Wow, merci pour la réponse massive, très intéressant. Bien sûr, je vais devoir le relire plusieurs fois, mais j'aimerais savoir quelle serait la ressource la plus fiable pour apprendre à maîtriser le 6NF? Les résultats de Wikipedia et de Google ne sont pas si utiles. Où/Comment avez-vous appris cela? – Moak

+8

Merci pour les mots gentils. Il n'y a pas une telle source. Il y a de bons manuels. L'information disponible sur le net (pour n'importe quoi, pas seulement ce sujet étroit) est des déchets Wiki est une étude de médiocrité. Vous obtenez ce que vous cherchez. Un diplôme d'informatique formel d'un bon Uni est le meilleur endroit pour commencer. Comme vous le savez, la maîtrise vient du travail avec un maître. AFAIK seul un autre co fournit ce niveau de maîtrise sur le sujet: ils le vendent comme un produit; Je le vends comme un service, parce que je crois que le client doit vraiment le comprendre, le posséder, ne pas l'enfermer dans un produit. – PerformanceDBA

+2

Où/comment. Eh bien, j'ai fait tout ce qui précède, et je suis très reconnaissant pour les excellents enseignants que j'ai eu. J'améliore environ quatre bases de données par an, pour les grandes banques, c'est ma passion/profession. Si j'en dis plus ici, ce serait impudique. Si vous êtes intéressé par plus de détails, chassez-moi: profile⇢website⇢email. Je serais libre de répondre à votre question. À votre santé. – PerformanceDBA

2

L'approche "abstraite" est mieux connue sous le nom de "normalisation", ressemble à la 3ème forme normale (3NF).

L'autre est appelé "dénormalisé" et peut être une option de performance valide ... lorsque vous avez rencontré des problèmes de vitesse en utilisant l'approche normalisée, pas avant.

+0

Donc, vous voulez dire qu'il faut construire l'approche normalisée et si la performance est vraiment un problème, soit mettre à niveau le matériel ou changer tout le code et créer de nouvelles tables? Désolé, je ne suis pas entièrement sûr de ce que vous me dites ... – Moak

+0

@Moak: Oui. Faire une approche dénormalisée sans avoir besoin d'une optimisation prématurée. –

+0

Comme je ne connais pas ces formes normales, pourriez-vous suggérer si je devrais peut-être examiner la première, deuxième, quatrième, fith ou autre forme normale? – Moak

1

Comment avez-vous les listes représentées dans le code? Je devine Listing comme un supertype, avec Shop, Restuarant, etc. comme sous-types? En supposant qu'il en soit ainsi, il s'agit d'un cas de mappage de sous-types à une base de données relationnelle. Il y a généralement trois choix:

  • Option 1: une seule table par sous-type, avec des attributs communs répétés dans chaque table (nom, id, etc.).
  • Option 2: table unique pour tous les objets (votre approche de table unique)
  • Option 3: table pour le super-type et un pour chaque sous-type

Il n'y a pas une solution universellement correcte. Ma préférence est généralement de commencer par l'option 3; il fournit une structure de base de travail avec laquelle travailler, est assez bien normalisé et peut facilement être étendu. Cela signifie une seule jointure pour récupérer chaque instance - mais les SGBDR sont bien optimisés pour effectuer des jointures, ce qui ne cause pas vraiment de problèmes de performance en pratique.

L'option 2 peut être plus performante pour les requêtes (pas de jointures) mais pose des problèmes si les autres tables doivent se référer à toutes les instances de supertype (prolifération de clés étrangères).

L'option 1 semble à première vue être la plus performante, bien que 2 mises en garde: (1) Il n'est pas résilient à changer. Si vous ajoutez un nouveau sous-type (et donc des attributs différents), vous devrez modifier la structure de la table et la migrer. (2) Il peut être moins efficace qu'il n'y paraît. Étant donné que la population de tables est clairsemée, certaines bases de données ne la stockent pas de manière particulièrement efficace. En conséquence, il peut être moins efficace que l'option 1 - puisque le moteur de recherche peut faire des jointures plus rapidement qu'il ne peut rechercher des espaces de table clairsemés.

Le choix consiste en fait à connaître les détails de votre problème.Je suggère de lire un peu sur les options: this article est un bon endroit pour commencer.

HTH

8

Dans votre question, vous avez présenté au moins deux problèmes majeurs en même temps. Ces deux questions sont E-A-V et gen-spec.

D'abord, parlons de E-A-V. Votre dernière table (object_id, field_id, value) est essentiellement un E-A-V.Il y a un avantage à E-A-V et un inconvénient à E-A-V. L'avantage est que la structure est si générique qu'elle peut accueillir presque n'importe quel corps de données décrivant presque n'importe quel sujet. Cela signifie que vous pouvez procéder à la conception et à la mise en œuvre sans analyse de données ni compréhension du sujet, et ne vous inquiétez pas d'hypothèses erronées. L'inconvénient est qu'au moment de la récupération, vous devez faire l'analyse des données que vous avez omis avant de construire la base de données, afin de trouver des requêtes qui signifient n'importe quoi. C'est beaucoup plus grave que l'efficacité de la récupération. Mais vous allez aussi avoir de terribles problèmes avec l'efficacité de récupération. Il n'y a que deux façons d'apprendre à propos de cet écueil: vivez-le ou lisez-le à propos de ceux qui l'ont fait. Je recommande la lecture.

Deuxièmement, vous avez un cas de gen-spec. Votre table (object_id, type_id) capture un modèle gen-spec (généralisation-spécialisation), ainsi que les tables associées. Si je devais généraliser entre les hôtels et les restaurants, je pourrais appeler cela quelque chose comme «les lieux publics» ou «lieux». Mais je ne suis pas sûr de comprendre votre cas, et vous conduisez peut-être pour quelque chose de plus général que ne le suggèrent ces deux noms. Après tout, vous avez inclus des «événements» dans votre liste, et un événement n'est pas un type de lieu dans mon esprit.

J'ai référé à d'autres personnes des lectures sur gen-spec et le modèle relationnel dans les réponses précédentes.
When two tables are very similar, when should they be combined?

Mais je hésite à vous envoyer dans la même direction, parce que ce n'est pas clair pour moi que vous voulez trouver un modèle relationnel des données avant de construire votre base de données. Un modèle relationnel d'un corps de données et un modèle E-A-V des mêmes données sont presque totalement en désaccord l'un avec l'autre. Il me semble que vous devez faire ce choix avant même d'explorer comment exprimer la spécification générique dans le modèle relationnel des données.

1

Lorsque vous commencez à avoir besoin d'un grand nombre d'entités différentes (ou même avant ...), une solution nosql serait beaucoup plus simple que n'importe quel choix. Il suffit de stocker chaque entité/enregistrement avec les champs exacts dont vous avez besoin.

{ 
    "id": 1, 
    "type":"Restaurant", 
    "name":"Messy Joe", 
    "address":"1 Main St.", 
    "tags":["asian","fusion","casual"] 
}