通常、階層には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