Mysql
 sql >> Base de données >  >> RDS >> Mysql

Quel modèle hiérarchique dois-je utiliser ? Contiguïté, imbriquée ou énumérée ?

Généralement, il existe trois types de requêtes dans les hiérarchies qui causent des problèmes :

  1. Renvoyer tous les ancêtres
  2. Renvoyer tous les descendants
  3. Renvoyer tous les enfants (descendants immédiats).

Voici un petit tableau qui montre les performances des différentes méthodes dans MySQL :

                        Ancestors  Descendants  Children        Maintainability InnoDB
Adjacency list          Good       Decent       Excellent       Easy            Yes
Nested sets (classic)   Poor       Excellent    Poor/Excellent  Very hard       Yes
Nested sets (spatial)   Excellent  Very good    Poor/Excellent  Very hard       No
Materialized path       Excellent  Very good    Poor/Excellent  Hard            Yes

Dans children , poor/excellent signifie que la réponse dépend si vous mélangez la méthode avec la liste de contiguïté, c'est-à-dire. e. stocker le parentID dans chaque enregistrement.

Pour votre tâche, vous avez besoin des trois requêtes :

  1. Tous les ancêtres pour montrer le truc Terre / Royaume-Uni / Devon
  2. Tous les enfants doivent montrer "Destinations en Europe" (les articles)
  3. Tous les descendants doivent afficher "Destinations en Europe" (les chiffres)

J'opterais pour des voies matérialisées, car ce type de hiérarchie change rarement (uniquement en cas de guerre, de révolte, etc.).

Créez une colonne varchar appelée path , indexez-le et remplissez-le avec la valeur comme ceci :

1:234:6345:45454:

où les nombres sont les clés primaires des parents appropriés, dans le bon ordre (1 pour l'Europe, 234 pour le Royaume-Uni, etc.)

Vous aurez également besoin d'un tableau appelé levels pour conserver les nombres à partir de 1 à 20 (ou le niveau d'imbrication maximal que vous souhaitez).

Pour sélectionner tous les ancêtres :

SELECT   pa.*
FROM     places p
JOIN     levels l
ON       SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN     places pa
ON       pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':') 
WHERE    p.id = @id_of_place_in_devon

Pour sélectionner tous les enfants et le nombre de lieux qu'ils contiennent :

SELECT  pc.*, COUNT(pp.id)
FROM    places p
JOIN    places pc
ON      pc.parentId = p.id
JOIN    places pp
ON      pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
        AND pp.id NOT IN
        (
        SELECT  parentId
        FROM    places
        )
WHERE   p.id = @id_of_europe
GROUP BY
        pc.id