Обработка данных иерархии в базе данных

Мне любопытно узнать, как лучше всего (наилучшая практика) обрабатывать иерархии в отношении дизайна базы данных. Вот небольшой пример того, как я обычно с ними справляюсь.

Таблица узлов

NodeId int PRIMARY KEY
NodeParentId int NULL
DisplaySeq int NOT NULL
Title nvarchar(255)

Таблица предков

NodeId int
AncestorId int
Hops int

с индексами на NodeId, AncestorId, Hops

Таблицы выглядят так:

Таблица узлов

NodeId    NodeParentId    DisplaySeq    Title
1         NULL            1             'Root'
2         1               1             'Child 1'
3         1               2             'Child 2'
4         2               1             'Grandchild 1'
5         2               2             'Grandchild 2'

Таблица предков

NodeId    AncestorId    Hops
1         NULL          0
1         1             0
2         1             1
2         2             0
3         1             1
3         3             0
4         1             2
4         2             1
4         4             0
5         1             2
5         2             1
5         5             0

При таком дизайне я обнаружил, что с большими иерархиями я могу очень быстро получить весь раздел иерархии, присоединившись к таблице Ancestor для AncestorId = target NodeId, например:

SELECT *
FROM Node n
INNER JOIN Ancestor a on a.NodeId=n.NodeId
WHERE a.AncestorId = @TargetNodeId

Также легко получить прямых детей

SELECT *
FROM Node n
INNER JOIN Ancestor a on a.NodeId=n.NodeId
WHERE a.AncestorId = @TargetNodeId
AND Hops = 1

Мне интересно узнать, какие еще решения вы могли использовать для такого рода вещей. По моему опыту, иерархии могут быть довольно сложными, и любой способ оптимизации их поиска очень важен.

Ответов (6)

Решение

Как уже отметили MarkusQ и n8wrl, у Джо Селко есть кое-что по этому поводу. Я просто добавлю, что существует несколько способов моделирования иерархии (я считаю, что книга Джо содержит несколько, а не только один, который он считает «лучшим»). Надеемся, что ваше окончательное решение будет учитывать ваши собственные потребности. Некоторые из различных способов моделирования лучше подходят для операций с интенсивной записью, в то время как другие лучше для частого или быстрого чтения вверх и вниз по иерархии. Просто имейте в виду, что ваша система будет с этим делать.

В SQL Server 2008 появился тип данных hierarchyid.

Вы также можете проверить шаблон «вложенные наборы»:

http://www.intelligententerprise.com/001020/celko.jhtml (неработающая ссылка)

Или вы можете найти в Google больше.

PS: Curses, n8wrl , ты печатаешь быстрее меня!

В Oracle вы можете использовать CONNECT BY / START WITH для запроса иерархических данных. В SQL Server вы можете использовать хранимую процедуру, которая вызывает себя рекурсивно.

Для этого есть несколько расширений, зависящих от поставщика, но мой любимый способ, не зависящий от базы данных, исходит от Джо Селко - загуглите «Деревья и иерархии Джо Селко» или купите эту книгу: текст ссылки

Это очень умный подход, основанный на множестве вещей. Легко запрашивать иерархию. Я добавил поле «parentID», которое у вас есть, только потому, что я часто задаю вопросы «прямым потомкам» и «родителям», и это ускоряет их. Но это прекрасный способ получить запрос «происхождение» или «описание».

Я определенно рекомендую вложенные наборы. Они великолепны.

http://threebit.net/tutorials/nestedset/tutorial1.html http://www.dbmsmag.com/9603d06.html