Как реализовать высокопроизводительное древовидное представление в SQL Server 2005

Как лучше всего построить таблицу, которая будет представлять дерево? Я хочу реализовать выбор, вставку, обновление и удаление, которые будут хорошо работать с большими данными. Выбор, например, должен будет поддерживать «Расширить ВСЕ» — получение всех дочерних элементов (и дочерних элементов) для данного узла.


person SirMoreno    schedule 12.05.2009    source источник


Ответы (5)


Используйте CTE.

Учитывая древовидную структуру таблицы:

id parent name
1  0      Electronics
2  1      TV
3  1      Hi-Fi
4  2      LCD
5  2      Plasma
6  3      Amplifiers
7  3      Speakers

, этот запрос вернет id, parent и уровень глубины, упорядоченные в виде дерева:

WITH    v (id, parent, level) AS
        (
        SELECT  id, parent, 1
        FROM    table
        WHERE   parent = 0
        UNION ALL
        SELECT  id, parent, v.level + 1
        FROM    v
        JOIN    table t
        ON      t.parent = v.id
        )
SELECT  *
FROM    v

id parent name
1  0      Electronics
2  1        TV
4  2          LCD
5  2          Plasma
3  1        Hi-Fi
6  3          Amplifiers
7  3          Speakers

Замените parent = 0 на parent = @parent, чтобы получить только ветвь дерева.

При наличии индекса table (parent) этот запрос будет эффективно работать с очень большой таблицей, поскольку он будет рекурсивно использовать INDEX LOOKUP для поиска всех дочерних элементов для каждого родителя.

Чтобы обновить определенную ветку, введите:

WITH    v (id, parent, level) AS
        (
        SELECT  id, parent, 1
        FROM    table
        WHERE   parent = 0
        UNION ALL
        SELECT  id, parent, v.level + 1
        FROM    v
        JOIN    table t
        ON      t.parent = v.id
        )
UPDATE  table t
SET     column = newvalue
WHERE   t.id IN
        (
        SELECT  id
        FROM    v
        )

где @parent — корень ветки.

person Quassnoi    schedule 12.05.2009
comment
Не могли бы вы подробнее рассказать о структуре таблиц? будет ли этот запрос хорошо работать с большой базой данных? - person SirMoreno; 13.05.2009
comment
спасибо, как можно сделать глубокое обновление? - обновить все узлы под родителем? (включая внуков) - person SirMoreno; 14.05.2009
comment
эй, я пытаюсь заставить это работать, и похоже, что элемент vq не работает, хотя я пытаюсь в 2008 году. Также должен ли уровень храниться в базе данных, так как он не показан в таблице? - person Chris Barry; 03.09.2009
comment
@optician: попробуй сейчас. Level — это псевдостолбец, он генерируется и вычисляется в CTE. - person Quassnoi; 03.09.2009

Сначала вы должны задать себе следующие вопросы: 1) Каково соотношение модификаций и чтений? (= в основном статическое дерево или постоянно меняющееся?) 2) Как глубоко и насколько вы ожидаете, что дерево будет расти?

Вложенные наборы отлично подходят для в основном статических деревьев, где вам нужны операции над целыми ветвями. Без проблем справляется с глубокими деревьями.

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

Рекурсивные CTE идеально подходят для очень маленьких деревьев, но операции ветвления ("получить все дочерние элементы в этой ветке...") становятся очень дорогостоящими с глубоким/большим деревом.

person Community    schedule 17.05.2009
comment
Мое дерево очень динамично, много обновлений, но и много выборок. А хотелось бы иметь возможность прокачиваться до 10-15 уровней. Я нашел эту статью о вложенных наборах: sqlblog.com/blogs/adam_machanic/archive/2006/07/12/ Будут ли вложенные наборы, как описано в этой статье, моим лучшим вариантом? ? Спасибо. - person SirMoreno; 27.05.2009

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

person Tom H    schedule 12.05.2009
comment
Спасибо посмотрю. Является ли объединение более эффективным, чем рекурсивное? Я слышал, что в mssql 2005 есть новый способ работы с деревьями. Вы не знаете, хорошо ли он работает с большими БД? - person SirMoreno; 12.05.2009
comment
UNION ALL в CTE является рекурсивным, хотя я не уверен, как SQL Server обрабатывает его за кулисами или есть ли для него настройки производительности. Я не проводил достаточно масштабных тестов с CTE, чтобы с уверенностью сказать о производительности. - person Tom H; 13.05.2009

Если у вас много обновлений и выборок, лучшим вариантом будет Модель перечисления путей, которая кратко описана здесь:

http://www.sqlteam.com/article/more-trees-hierarchies-in-sql

person pyfex    schedule 30.09.2009

Я удивлен, что никто не упомянул о таблице закрытия. Очень эффективен для чтения и довольно прост в написании.

person Christopher Smith    schedule 16.03.2014