通常、階層には3種類のクエリがあり、問題が発生します。
- すべての祖先を返す
- すべての子孫を返す
- すべての子(直系の子孫)を返します。
これは、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
children
、poor/excellent
つまり、答えは、メソッドを隣接リストと混合しているかどうかによって異なります。 e。 parentID
を保存する 各レコードで。
タスクには、次の3つのクエリすべてが必要です。
- 地球/イギリス/デボンのことを示すすべての祖先
- 「ヨーロッパの目的地」(アイテム)を表示するすべての子供
- 「ヨーロッパの目的地」を表示するすべての子孫(カウント)
この種の階層はめったに変更されないので、私は具体化された道を選びます(戦争、反乱などの場合のみ)。
path
というvarchar列を作成します 、インデックスを作成し、次のような値を入力します:
1:234:6345:45454:
ここで、番号は適切な親の主キーであり、正しい順序になっています(1
ヨーロッパの場合、234
英国など)
levels
というテーブルも必要になります 1
からの数字を保持する 20
へ (または必要な最大ネストレベル)。
すべての祖先を選択するには:
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
すべての子とその中の場所の数を選択するには:
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