#oracle #plsql #query-optimization #hierarchical-query
Вопрос:
у меня есть таблица с 4 миллионами записей, которые содержат parent_id и child_id и таблицу персон с полем флага в oracle, мне нужен код plsql с циклом for и одним идентификатором персоны для ввода, который получает все отношения этого человека, входной идентификатор будет одним из идентификаторов в таблице персон, которые имеют значение » 1 » в поле флага я написал этот код plsql, но он слишком медленный, пожалуйста, помогите улучшить производительность?
FOR rec1 IN (SELECT p.ID
FROM PERSONS p
WHERE p.CHANGE_FLAG = '1')
LOOP
INSERT INTO TEST_CYCLE (person_id)
WITH cte (id) AS (
SELECT r.PARENT_PERSON_ID
FROM PERSON_FAMILY r
WHERE rec1.id IN (r.CHILD_PERSON_ID, r.PARENT_PERSON_ID)
UNION ALL
SELECT CASE
WHEN c.id = t.PARENT_PERSON_ID
THEN t.CHILD_PERSON_ID
ELSE t.PARENT_PERSON_ID
END
FROM PERSON_FAMILY t
JOIN cte c
ON c.id IN (t.CHILD_PERSON_ID, t.PARENT_PERSON_ID)
)
CYCLE id SET is_cycle TO '1' DEFAULT 0
SELECT c.id
FROM cte c;
END LOOP;
Комментарии:
1. Пожалуйста, покажите план выполнения запроса и опишите, что вы считаете «медленным». Рекурсивный запрос все равно не быстрый
Ответ №1:
Не используйте FOR
цикл и делайте все это в одном запросе:
INSERT INTO TEST_CYCLE (person_id)
WITH cte (pid, id) AS (
SELECT p.id,
r.PARENT_PERSON_ID
FROM PERSON_FAMILY r
INNER JOIN PERSONS p
ON p.id IN (r.CHILD_PERSON_ID, r.PARENT_PERSON_ID)
WHERE p.CHANGE_FLAG = '1'
UNION ALL
SELECT c.pid,
CASE
WHEN c.id = t.PARENT_PERSON_ID
THEN t.CHILD_PERSON_ID
ELSE t.PARENT_PERSON_ID
END
FROM PERSON_FAMILY t
JOIN cte c
ON c.id IN (t.CHILD_PERSON_ID, t.PARENT_PERSON_ID)
)
CYCLE pid, id SET is_cycle TO '1' DEFAULT 0
SELECT c.id
FROM cte c;