Прежде всего, я бы рекомендовал использовать parent = NULL
вместо нуля для обозначения корневого узла, что позволило бы tree
иметь внешний ключ на parent
, который ссылается на id
;ссылочная целостность полезна.
Затем вы можете включить материализованный путь от корневого узла к текущему узлу в каждой строке.Материализованный путь был бы строковым столбцом, который представляет путь от корневого узла до текущего узла;для ваших целей вы хотите использовать формат фиксированной ширины для каждого узла в пути, затем вы можете ASCIIbetical сортировать пути для извлечения записей в древовидном порядке (как в этом answer ).
Предположим, вы думали, что 99999 будет достаточно, чтобы покрыть все ваши узлы.Тогда у вас может быть строковый путь, подобный следующему:
'00001000110002300042'
Это будет представлять последовательность идентификаторов [1, 11, 23, 42]
, так что родительским узлом будет 42, прародителем 23 и так далее до корня 1.Чтобы получить всю ветку от узла к корню: возьмите путь, разделите его на части, чтобы получить идентификаторы, и извлеките все узлы одновременно, сортируя по материализованному пути, чтобы получить их в правильном порядке.
Этот подход также позволяет легко извлекать целые поддеревья сразу: просто создайте префикс пути, соответствующий желаемому поддереву, и выполните команду path LIKE 'pfx%' ORDER BY path, id
, чтобы извлечь целое поддерево за один проход.Кроме того, большинство баз данных будет использовать индекс для выражения LIKE, который имеет корни в начале (т. Е. LIKE 'X%'
для некоторых X
), поэтому запросы такого типа могут выполняться довольно быстро.Вы также можете вычислить глубину узла с помощью простой длины строки и вычисления деления.
Вам нужно проделать небольшую дополнительную работу, чтобы построить материализованные пути, но не так много, и они выполняют много операций с деревом.красиво и просто, сохраняя при этом преимущества естественного представления дерева.