sql >> Databasteknik >  >> RDS >> Mysql

Vilken hierarkisk modell ska jag använda? Närliggande, kapslad eller uppräknad?

Vanligtvis finns det tre typer av frågor i hierarkierna som orsakar problem:

  1. Tillbaka alla förfäder
  2. Tillbaka alla ättlingar
  3. Tillbaka alla barn (direkta ättlingar).

Här är en liten tabell som visar prestanda för olika metoder i 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

I children , poor/excellent betyder att svaret beror på om du blandar metoden med adjacency list, dvs. e. lagra parentID i varje post.

För din uppgift behöver du alla tre frågorna:

  1. Alla förfäder för att visa Earth / UK / Devon-grejen
  2. Alla barn ska visa "Destinationer i Europa" (objekten)
  3. Alla ättlingar ska visa "Destinationer i Europa" (antalerna)

Jag skulle gå för materialiserade vägar, eftersom denna typ av hierarki sällan förändras (endast vid krig, revolt etc).

Skapa en varchar-kolumn som heter path , indexera det och fyll det med värdet så här:

1:234:6345:45454:

där siffrorna är primärnycklar för lämpliga föräldrar, i korrekt ordning (1 för Europa, 234 för Storbritannien etc.)

Du behöver också en tabell som heter levels för att behålla nummer från 1 till 20 (eller vilken maximal häckningsnivå du vill ha).

Så här väljer du alla förfäder:

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

Så här väljer du alla barn och antal platser inom dem:

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. Spotlight Cloud Security Feature - Ta bort bokstaver

  2. Hur ansluter man Android-appen till MySQL-databasen?

  3. Radmönsterigenkänning i SQL

  4. Fel vid Update Join