In genere, ci sono tre tipi di query nelle gerarchie che causano problemi:
- Restituisci tutti gli antenati
- Restituisci tutti i discendenti
- Restituisci tutti i figli (discendenti immediati).
Ecco una piccola tabella che mostra le prestazioni di diversi metodi in 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
In children
, poor/excellent
significa che la risposta dipende dal fatto che stai mescolando il metodo con l'elenco di adiacenza, i. e. memorizzazione del parentID
in ogni record.
Per il tuo compito, hai bisogno di tutte e tre le query:
- Tutti gli antenati mostreranno la cosa Terra/Regno Unito/Devon
- Tutti i bambini mostreranno "Destinazioni in Europa" (gli oggetti)
- Tutti i discendenti mostreranno "Destinazioni in Europa" (i conti)
Andrei per strade materializzate, poiché questo tipo di gerarchia cambia raramente (solo in caso di guerra, rivolta, ecc.).
Crea una colonna varchar chiamata path
, indicizzalo e riempilo con il valore in questo modo:
1:234:6345:45454:
dove i numeri sono chiavi primarie dei genitori appropriati, nell'ordine corretto (1
per l'Europa, 234
per il Regno Unito ecc.)
Avrai anche bisogno di una tabella chiamata levels
per mantenere i numeri da 1
a 20
(o qualsiasi livello di nidificazione massimo che desideri).
Per selezionare tutti gli antenati:
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
Per selezionare tutti i bambini e il conteggio dei posti al loro interno:
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