Meestal zijn er drie soorten zoekopdrachten in de hiërarchieën die problemen veroorzaken:
- Geef alle voorouders terug
- Geef alle nakomelingen terug
- Geef alle kinderen terug (directe afstammelingen).
Hier is een kleine tabel die de prestaties van verschillende methoden in MySQL
laat zien :
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
In children
, poor/excellent
betekent dat het antwoord afhangt van of u de methode mengt met de lijst met aangrenzende gebieden, i. e. opslaan van de parentID
in elk record.
Voor je taak heb je alle drie de vragen nodig:
- Alle voorouders om het Earth / UK / Devon-ding te laten zien
- Alle kinderen tonen "Bestemmingen in Europa" (de items)
- Alle nakomelingen om "Bestemmingen in Europa" te tonen (de tellingen)
Ik zou gaan voor gematerialiseerde paden, aangezien dit soort hiërarchie zelden verandert (alleen in geval van oorlog, opstand enz.).
Maak een varchar-kolom met de naam path
, indexeer het en vul het met de waarde als volgt:
1:234:6345:45454:
waarbij de nummers de primaire sleutels zijn van de betreffende ouders, in de juiste volgorde (1
voor Europa, 234
voor VK enz.)
Je hebt ook een tabel nodig met de naam levels
om nummers van 1
te behouden tot 20
(of welk maximaal nestniveau je maar wilt).
Om alle voorouders te selecteren:
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
Om alle kinderen te selecteren en plaatsen binnen hen te tellen:
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