У меня есть таблица, представляющая график связей иерархии (parent_id, child_id) В таблице указаны индексы родительского, дочернего и обоих. Граф может содержать циклы, и мне нужно их проверить (или, может быть, мне нужно найти все циклы, чтобы их устранить).postgresql игнорирует индекс для рекурсивного запроса
И мне нужно запросить всех родителей узла. Для этого я использую этот запрос (предполагается, должны быть сохранены в виде):
WITH RECURSIVE recursion(parent_id, child_id, node_id, path) AS (
SELECT h.parent_id,
h.child_id,
h.child_id AS node_id,
ARRAY[h.parent_id, h.child_id] AS path
FROM hierarchy h
UNION ALL
SELECT h.parent_id,
h.child_id,
r.node_id,
ARRAY[h.parent_id] || r.path
FROM hierarchy h JOIN recursion r ON h.child_id = r.parent_id
WHERE NOT r.path @> ARRAY[h.parent_id]
)
SELECT parent_id,
child_id,
node_id,
path
FROM recursion
where node_id = 883
Для этого запроса Postgres собирается использовать очень потрясающий план:
"CTE Scan on recursion (cost=2703799682.88..4162807558.70 rows=324223972 width=56)"
" Filter: (node_id = 883)"
" CTE recursion"
" -> Recursive Union (cost=0.00..2703799682.88 rows=64844794481 width=56)"
" -> Seq Scan on hierarchy h (cost=0.00..74728.61 rows=4210061 width=56)"
" -> Merge Join (cost=10058756.99..140682906.47 rows=6484058442 width=56)"
" Merge Cond: (h_1.child_id = r.parent_id)"
" Join Filter: (NOT (r.path @> ARRAY[h_1.parent_id]))"
" -> Index Scan using hierarchy_idx_child on hierarchy h_1 (cost=0.43..256998.25 rows=4210061 width=16)"
" -> Materialize (cost=10058756.56..10269259.61 rows=42100610 width=48)"
" -> Sort (cost=10058756.56..10164008.08 rows=42100610 width=48)"
" Sort Key: r.parent_id"
" -> WorkTable Scan on recursion r (cost=0.00..842012.20 rows=42100610 width=48)"
Похоже, Postgres не понять, что внешний фильтр на node_id применяется к child_id в первом рекурсивном подзапросе.
Я полагаю, что я делаю очень неправильно. Но где именно?
Как правило, в первой части UNION есть условие: либо верхний узел (не имеет родителя), либо листовой узел (не имеет дочерних элементов), либо какая-то конкретная запись #, которую вы интересуете. * каждый * запись как цепной стартер. – wildplasser
Первый запрос объединения извлекает ** все ** строки таблицы. Никакой индекс не поможет с этим –
Я надеялся, что postgres могут объединить внешний фильтр с внутренним подзапросом. Кажется, я слишком оптимистичен. – qMax