Вложенные в Oracle предложения CONNECT BY приводят к снижению производительности - PullRequest
0 голосов
/ 08 февраля 2019

Запрос ниже занимает около минуты.Я полагаю, что низкая производительность вызвана двумя предложениями IN (SELECT ...). У меня есть таблица терминов, где один может быть связан с другим через таблицу term_relationship. Эти отношения могут быть рекурсивными, например, тип собакимлекопитающее, млекопитающее - это тип животного. Эта рекурсия может быть любой глубины, но, вероятно, не более ~ 10 уровней. Я пытаюсь выбрать все термины, которые имеют (потенциально рекурсивное) отношение с типом А и имеют (потенциально рекурсивное) отношениес типом B. Я думаю, что замена двух предложений «IN (SELECT ...» на ограничения внешнего запроса) может повысить производительность, но не может понять, как это сделать с помощью предложений CONNECT BY. Кто-нибудь может помочь с этим?

SELECT term_name
FROM term
WHERE term_id IN 
   (SELECT term_id 
    FROM term_relationship 
    START WITH related_term_id = 123
    CONNECT BY NOCYCLE PRIOR term_id = related_term_id)
AND term_id IN 
   (SELECT term_id 
    FROM term_relationship 
    START WITH related_term_id = 456
    CONNECT BY NOCYCLE PRIOR term_id = related_term_id)

1 Ответ

0 голосов
/ 08 февраля 2019

Вместо того, чтобы выполнять один и тот же запрос CONNECT BY дважды, только с разными начальными значениями, как насчет того, чтобы сделать это один раз, предоставив оба начальных значения одному экземпляру подзапроса.Это изменение даст вам все term_id, связанные с любым из ваших начальных значений, однако вы хотите, чтобы только те term_id имели отношение к обоим из ваших начальных значений.Чтобы получить это, вам нужно сгруппировать результаты по term_id и ограничить их результатами, имеющими более одного счетчика:

SELECT term_name
  FROM term
 WHERE term_id IN 
    (SELECT term_id 
       FROM term_relationship 
      START WITH related_term_id in (123, 456)
    CONNECT BY NOCYCLE PRIOR term_id = related_term_id
      group by term_id having count(*) >= 2)

Редактировать
С кодом вышеЯ сделал предположение о ваших данных, которые могут быть неверными.Я предположил древовидную структуру, в которой вы начинали с узлов на ветке и двигались вверх к корню, как на диаграмме A, однако, если ваши данные выглядят как диаграмма B, тогда приведенный выше запрос не будет выполнен, если вы начнете с узлов 7 и 9поскольку у узла 7 есть два пути назад к узлу 1, и вышеупомянутый запрос дважды возвратит узел 1, тем самым неправильно идентифицируя его как общий узел.

A)   -(1)-                    B)   -(1)-
    /  |  \     (8)               /  |  \     (8)
  (2)  |  (3)    |              (2)  |  (3)    |
   |  (4)  |    (9)              |  (4)  |    (9)
  (5)     (6)                   (5)     (6)
           |                      \     /
          (7)                      -(7)-

Запрос ниже исправляет это и правильно идентифицирует это дляВ начальных узлах 7 и 9 нет общих узлов, однако с начальными узлами 7 и 4 узел 1 идентифицируется как общий узел:

SELECT term_name
  FROM term
 WHERE term_id IN 
    (SELECT term_id 
     FROM term_relationship 
    START WITH related_term_id in (123, 456)
  CONNECT BY NOCYCLE PRIOR term_id = related_term_id
    group by term_id
   having count(distinct connect_by_root related_term_id) >= 2)
...