Приходилось ли работать с рекурсией в PostgreSQL
Что проверяют
Знаете ли вы рекурсивные обобщённые табличные выражения и понимаете ли, чем они опасны на реальных данных. Для .NET-разработчика вопрос двойной: сам запрос и то, как он выполняется из приложения, ведь через LINQ такой запрос не выражается.
Как отвечать
Речь про WITH RECURSIVE: якорная часть, UNION ALL и рекурсивная часть, ссылающаяся на само выражение. Классическая задача это дерево категорий или подчинённых.
WITH RECURSIVE tree AS (
SELECT id, parent_id, 1 AS depth
FROM categories WHERE id = @root
UNION ALL
SELECT c.id, c.parent_id, t.depth + 1
FROM categories c JOIN tree t ON c.parent_id = t.id
WHERE t.depth < 10
)
SELECT * FROM tree;Отдельно проговорите защиту от циклов: UNION вместо UNION ALL отсекает повторы, ограничение глубины страхует от зацикливания, надёжнее всего накапливать массив пройденных идентификаторов и проверять вхождение. Со стороны C# такой запрос выполняют сырым SQL через Dapper или FromSqlRaw, параметры передают параметрами, а не склейкой строк. Если дерево читают часто, а меняют редко, назовите альтернативы: материализованный путь, расширение ltree, таблица связей всех предков.
Где спотыкаются
Считают, что база сама остановит бесконечную рекурсию. Цикл в данных, например узел, ставший собственным предком после неудачного переноса, заставит запрос крутиться, пока не кончится память или не сработает ограничение на время выполнения.
Второе: забывают индекс по parent_id. Каждый шаг рекурсии превращается в полный скан таблицы, и дерево из тысячи узлов считается секундами вместо миллисекунд, причём на маленьком справочнике это незаметно.
Третье: обходят дерево в приложении. Рекурсивный метод на C#, делающий запрос на каждый узел, даёт сотни обращений к базе там, где хватало одного, и это классический N+1 в самом дорогом его виде.