повышение производительности родительского дочернего запроса

#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;