Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Który model hierarchiczny powinienem użyć? Sąsiedztwo, zagnieżdżone czy wyliczone?

Zazwyczaj w hierarchii występują trzy rodzaje zapytań, które powodują problemy:

  1. Zwróć wszystkich przodków
  2. Zwróć wszystkich potomków
  3. Zwróć wszystkie dzieci (bezpośrednich potomków).

Oto mała tabela, która pokazuje wydajność różnych metod w 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

W children , poor/excellent oznacza, że ​​odpowiedź zależy od tego, czy mieszasz metodę z listą sąsiedztwa, tj. mi. przechowywanie parentID w każdym rekordzie.

Do swojego zadania potrzebujesz wszystkich trzech zapytań:

  1. Wszyscy przodkowie, aby pokazać Ziemię/Wielką Brytanię/Devon
  2. Wszystkie dzieci mają pokazać „Miejsca docelowe w Europie” (przedmioty)
  3. Wszyscy potomkowie mają pokazać „Miejsca docelowe w Europie” (liczba)

Wybrałbym zmaterializowane ścieżki, ponieważ tego rodzaju hierarchia rzadko się zmienia (tylko w przypadku wojny, buntu itp.).

Utwórz kolumnę varchar o nazwie path , zindeksuj go i wypełnij wartością w ten sposób:

1:234:6345:45454:

gdzie liczby są kluczami podstawowymi odpowiednich rodziców, we właściwej kolejności (1 dla Europy, 234 dla Wielkiej Brytanii itp.)

Będziesz także potrzebować tabeli o nazwie levels aby zachować liczby od 1 do 20 (lub jakikolwiek inny maksymalny poziom zagnieżdżenia, jaki chcesz).

Aby wybrać wszystkich przodków:

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

Aby wybrać wszystkie dzieci i liczbę znajdujących się w nich miejsc:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. używać PHP do tworzenia tabeli HTML z zapytania MSQL, bez zduplikowanych wierszy?

  2. Railsy na OSX 10.11 El Capitan:Biblioteka nie załadowana:libmysqlclient.18.dylib

  3. Gdzie jest plik MySQL 5.7 my.cnf?

  4. Największa wartość z dwóch lub więcej pól

  5. Czy indeksy UNIQUE rozróżniają wielkość liter w MySQL?