Этот вопрос проверяет знание моделей хранения и сериализации иерархий в БД: adjacency list, nested sets, materialized path и JSON-структуры, а также их плюсы и ограничения.
Деревья можно хранить разными способами: через связи «родитель → потомок» (adjacency list), через диапазоны в вершинах (nested sets), через путь от корня (materialized path), либо в JSON-структурах.
Adjacency list прост и понятен, но делает сложными выборки поддеревьев. Nested sets оптимизируют чтение, но требуют дорогих обновлений. Materialized path удобен для поиска потомков по шаблону пути.
JSON полезен, когда структура часто меняется или не требует сложных запросов внутри БД.
Выбор зависит от частоты чтений, обновлений и сложности запросов к дереву.
Хранение деревьев — частая задача при работе с каталогами, меню, сущностями с вложенностью. Существуют несколько классических моделей.
Определение:Adjacency list — модель, в которой каждая запись хранит ссылку на своего родителя.
id
parent_id -- может быть NULL для корня
name
простая структура;
легко обновлять (менять родителя);
интуитивно понятно.
сложные выборки поддеревьев, требуется рекурсия;
чтение дерева без CTE может быть дорогим.
WITH RECURSIVE tree AS (
SELECT id, parent_id, name FROM nodes WHERE id = 1
UNION ALL
SELECT n.id, n.parent_id, n.name
FROM nodes n
JOIN tree t ON t.id = n.parent_id
)
SELECT * FROM tree;
Определение:Nested sets — модель, в которой каждая вершина хранит два индекса: left и right.
Поддерево — это диапазон left < x < right.
id
lft
rgt
name
быстрые выборки поддеревьев;
идеально для часто читаемых деревьев.
обновления дороги: перестраивается большая часть дерева;
сложно реализовать без вспомогательных функций.
SELECT * FROM nodes WHERE lft BETWEEN 10 AND 30;
Определение:Materialized path — модель, где каждая запись хранит путь от корня к узлу в виде строки.
id
path -- например, '1.5.9.'
name
простая реализация;
быстрая выборка потомков (LIKE '1.5.%');
легко перемещать узлы (обновление пути).
зависимость от строковых операций;
возможны дорогие массовые обновления при изменении пути.
SELECT * FROM nodes WHERE path LIKE '1.5.%';
Определение:JSON-иерархия — способ хранить дерево как вложенные JSON-объекты.
гибкость;
нет жёсткой схемы;
удобно, если дерево часто меняется или не слишком велико.
сложно делать SQL-запросы по структуре;
трудно поддерживать целостность;
хуже подходит для больших деревьев.
SELECT data->'children' FROM tree WHERE id = 1;
когда дерево часто изменяется;
когда глубина небольшая;
когда подходит рекурсивный CTE.
когда важны быстрые запросы чтения;
когда структура меняется редко.
удобен для древовидных каталогов;
хорош, когда запросы — в основном чтение поддерева.
когда дерево — часть модели, но не основной объект хранения;
когда нет сложных запросов внутри БД.
Если дерево часто обновляется → adjacency list.
Если дерево читается гораздо чаще, чем модифицируется → nested sets.
Если удобен путь как строка → materialized path.
Если структура гибкая или вспомогательная → JSON.