2010-11-27 22 views
2

Supposons que j'avais un certain nombre de produits (de quelques milliers à des centaines de milliers) qui devaient être catégorisés de manière hiérarchique. Comment est-ce que je modéliserais une telle solution dans une base de données?Modélisation de base de données: Comment classer des produits comme Amazon?

Est-ce une simple table parent-enfant comme ce travail:

product_category 
- id 
- parent_id 
- category_name 

Puis, dans ma table de produits, je voudrais juste faire ceci:

product 
- id 
- product_category_id 
- name 
- description 
- price 

Je crains que ce ne sera pas échelle. Au fait, j'utilise MySQL pour le moment.

+0

http://en.wikipedia.org/wiki/MPTT –

+0

Consultez la http://www.sitepoint.com/hierarchical-data-database/ pour organiser les catégories de manière hiérarchique Cela vous permettra d'éviter joint lors de l'obtention de hiérarchies. –

Répondre

4

Course à l'échelle. Cela fonctionnera très bien, c'est une structure couramment utilisée.

Inclure un level_no. Cela aidera dans le code, mais plus important, il est nécessaire d'exclure les doublons.

Si vous voulez une structure vraiment serrée, vous avez besoin de quelque chose comme le concept d'inodes Unix.

Vous pouvez avoir du mal à comprendre le code requis pour produire la hiérarchie, par exemple à partir d'un product, mais c'est un problème distinct.

Et s'il vous plaît changer

  • (product_category)) id à product_category_id
  • (productid-product_id
  • parent_id à parent_product_category_id

Réponses aux commentaires

  1. level_no. Jetez un oeil à ce modèle de données, il est une structure d'arborescence (par exemple, la fenêtre FlieManager Explorer.):

    Directory Data Model

    Voyez si vous pouvez lui donner un sens, c'est le concept de inode Unix. Les noms de fichiers doivent être uniques dans le nœud, d'où le second index. C'est en fait complet, mais certains développeurs de nos jours auront un ajustement hissy écrit le code requis pour naviguer dans la hiérarchie, les niveaux. Ces développeurs ont besoin d'un level_no pour identifier le niveau dans la hiérarchie avec laquelle ils traitent.

  2. Modifications recommandées. Oui, cela s'appelle de bonnes conventions de nommage. Je suis rigide à ce sujet, et je le publie, donc c'est une norme de nommage. Il y a des raisons à cela, qui vous apparaîtront clairement lorsque vous écrirez du SQL avec 3 ou 4 niveaux de jointures; surtout quand vous allez au même parent de deux façons différentes. Si vous recherchez SO, vous trouverez beaucoup de questions à ce sujet; toujours la même réponse. Il sera également highlit dans le prochain modèle que j'écris pour vous.

+0

pouvez-vous expliquer un peu plus le but de 'level_no'? En outre, les changements recommandés que vous avez mentionnés sont-ils alignés sur une sorte de convention de codage? – StackOverflowNewbie

+1

@SONewbie. Répondu dans mon message. – PerformanceDBA

0

Votre solution utilise le modèle de liste d'adjacence d'une hiérarchie. C'est de loin le plus commun.Il s'agira d'évoluer jusqu'à des milliers de produits. Le problème est qu'il nécessite une requête récursive ou des extensions spécifiques à SQL pour gérer une hiérarchie indéfiniment profonde.

Il existe d'autres modèles de hiérarchie. En particulier, il y a le modèle de jeu imbriqué. Le modèle de jeu imbriqué est bon pour récupérer le chemin de n'importe quel noeud dans une seule requête. C'est aussi bon pour récupérer n'importe quel sous-arbre désiré. C'est plus de travail pour le garder à jour. Beaucoup plus de travail.

Vous voudrez peut-être explorer brièvement avant de mordre plus que vous voulez mâcher.

Qu'allez-vous faire de la hiérarchie?

0

Je pense que votre gros problème est que c'est une lacune dans MySQL. Pour la plupart des SGBDR prenant en charge WITH et WITH RECURSIVE, vous ne devez effectuer qu'une seule analyse par niveau. Cela rend les hiérarchies profondes un peu problématiques mais généralement pas trop mauvaises.

Je pense que pour que cela fonctionne bien, vous devrez coder une procédure stockée assez étendue, ou vous devrez passer à un autre modèle d'arborescence, ou vous devrez passer à un SGBDR différent. Par exemple, cela est facile à faire avec PostgreSQL et WITH RECURSIVE, ce qui offre une meilleure évolutivité que beaucoup d'autres approches.

3

J'avais l'habitude de lutter avec le même problème il y a 10 ans. Voici ma solution personnelle à ce problème. Mais avant de commencer à expliquer, je voudrais mentionner ses avantages et ses inconvénients.

Plus:

  1. Vous pouvez sélectionner un sous-branches d'noeud donné dans un certain nombre de profondeurs désirées, avec le plus bas coût imaginables.

  2. La même chose peut être faite pour sélectionner les nœuds parents.

  3. Aucune fonctionnalité spécifique au SGBDR n'est requise. Ainsi, la même technique peut être implémentée dans l'un quelconque d'entre eux.

  4. Tout est implémenté en utilisant un seul champ.

Moins:

  1. Vous devriez être en mesure de définir un maximum de profondeur pour votre arbre . Vous devez également définir le nombre maximal d'enfants directs pour les nœuds.

  2. Restructurer l'arbre est plus coûteux que de le traverser. Mais pas aussi cher que Nest Set Model. Ajout d'une nouvelle branche est la question de trouver la bonne valeur pour le champ. Et afin de déplacer une branche dans un nouveau parent, vous devez mettre à jour ce nœud et tous ses enfants (direct et indirect). La bonne nouvelle est que la suppression d'un nœud et de ses enfants est aussi simple que de le traverser (ce qui n'est absolument rien).

La technique:

Tenir compte du tableau ci-dessous comme support d'arbre:

CREATE TABLE IF NOT EXISTS `product_category` (
    `product_category_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(20) NOT NULL, 
    `category_code` varchar(62) NOT NULL, 
    PRIMARY KEY (`product_category_id`), 
    UNIQUE KEY `uni_category_code` (`category_code`) 
) DEFAULT CHARSET=utf8 ; 

Toute la magie se fait dans category_code domaine. Vous devez encoder votre adresse de branchement en une valeur de texte comme suit:

**node_name -> category_code** 
Root -> 01 
First child -> 01:01 
Second child -> 01:02 
First grandchild -> 01:01:01 
First child of second child -> 01:02:01 

Dans l'exemple ci-dessus, chaque nœud peut contenir jusqu'à 99 enfants directs (à supposer que nous pensons en décimal). Et puisque category_code est de type varchar(62), nous pouvons avoir jusqu'à (62-2)/3 = 20 profondeur. C'est un compromis entre la profondeur que vous voulez et le nombre d'enfants directs que chaque nœud peut avoir et la taille de votre champ. Scientifiquement parlant, il s'agit d'une implémentation d'un complete tree dans lequel les branches inutilisées ne sont pas réellement créées mais réservées.

Les bonnes parties:

Maintenant, imaginez que vous voulez sélectionner des noeuds sous 01:02. Vous pouvez le faire en utilisant une seule requête:

SELECT * 
FROM product_category 
WHERE 
    category_code LIKE '01:02:%' 

Sélection des noeuds directs sous la 01:02:

SELECT * 
FROM product_category 
WHERE 
    category_code LIKE '01:02:__' 

La sélection de tous les ancêtres de 01:02:

SELECT * 
FROM product_category 
WHERE 
    '01:02' LIKE CONCAT(category_code, ':%') 

Les mauvaises parties:

Insertion d'un nouveau nœud dans l'arbre est la question de trouver le bon category_code. Cela peut être fait en utilisant une procédure stockée ou même dans un langage de programmation comme PHP.

Étant donné que l'arbre est limité par le nombre d'enfants directs et la profondeur, une insertion peut échouer. Mais je crois que dans la plupart des cas pratiques, nous pouvons supposer une telle limitation.

Cheers.