2010-10-13 2 views
2

У меня есть следующий SQL заявление:Oracle 10g Connect предшествующими - проблемы производительности

SELECT 
    CONNECT_BY_ROOT ANIMAL_ID "ORIGINAL_ANIMAL" , 
    ANIMAL_ID, LINE_ID, SIRE_ANIMAL_ID, DAM_ANIMAL_ID, 
    LEVEL -1 "LEVEL" FROM ANIMALS 
START WITH ANIMAL_ID IN('2360000002558') 
CONNECT BY 
    ((PRIOR SIRE_ANIMAL_ID = ANIMAL_ID and LEVEL < 5) OR (PRIOR DAM_ANIMAL_ID = ANIMAL_ID AND LEVEL < 5)) 

это в в таблице с примерно 1,6 миллиона животных. Каждая запись имеет Animal_Id, Sire_Animal_Id и Dam_Animal_Id (Sire = Father, Dam = Mother).

Я использую этот sql для отображения полной породы животных. Результаты покажут животных, 2 родителя, 4 GrandParents и т. Д.

Моя проблема заключается в том, что это заявление занимает 15 секунд для одного животного. Должен быть способ оптимизировать это. Есть предположения?

+6

Что такое план выполнения? Какие индексы существуют на столе? –

+0

Возможно, у вас есть это ИЛИ в соединении (смешивая два дерева в одной структуре), вы пробовали объединение двух отдельных запросов (один для дерева сир, второй для дерева дам)? – kurosch

ответ

0

Есть ли указатели на sire_animal_id и dam_animal_id? Это может быть полное сканирование таблицы.

0

Я попытался воссоздать вашу ситуацию, и я не смог заставить Oracle использовать индексы с умом. Я уверен, что есть разумный способ сделать это. Но если никто больше не может понять это, ниже - немой, уродливый путь.

Поскольку вы получаете только определенное количество уровней, вы можете вручную создать соединение. Получить первый уровень, объединить его со вторым уровнем (который получает результаты от копии первого запроса), объединить его на третий уровень (который получает результаты из копии второго запроса) и т. Д. Я сделал только три уровня здесь, но вы можете скопировать и вставить, чтобы сделать четвертый. Это сложнее, так как исходный идентификатор повторяется столько раз, но это очень быстро (0.005 секунд на моей машине с 1,6 миллиона записей.)

--Original animal 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 0 "level" from animals where animal_id = '101' 
union all 
--Parents 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 1 "level" from animals 
where animal_id = (select sire_animal_id from animals where animal_id = '101') 
union all 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 1 "level" from animals 
where animal_id = (select dam_animal_id from animals where animal_id = '101') 
union all 
--Grand parents 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 2 "level" from animals 
where animal_id = 
(
    select sire_animal_id from animals 
    where animal_id = (select sire_animal_id from animals where animal_id = '101') 
) 
union all 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 2 "level" from animals 
where animal_id = 
(
    select dam_animal_id from animals 
    where animal_id = (select sire_animal_id from animals where animal_id = '101') 
) 
union all 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 2 "level" from animals 
where animal_id = 
(
    select sire_animal_id from animals 
    where animal_id = (select dam_animal_id from animals where animal_id = '101') 
) 
union all 
select '101' original_animal, animal_id, line_id, sire_animal_id, dam_animal_id, 2 "level" from animals 
where animal_id = 
(
    select dam_animal_id from animals 
    where animal_id = (select dam_animal_id from animals where animal_id = '101') 
); 
0

У меня не было много времени, чтобы проверить это, так что это немного DYOR в ответе, но будет использовать встроенную поддержку просмотра?

Как вы еще не указали план объяснений, я не могу слишком сильно бояться, и в приведенном ниже решении вы можете обнаружить, что объединение в предложении WITH вызывает проблемы с производительностью, но может помочь вам ваш путь к решению.

WITH ani 
    AS (SELECT animal_id, 
      line_id, 
      sire_animal_id, 
      dam_animal_id, 
      sire_animal_id AS generic_id 
     FROM animals 
     UNION 
     SELECT animal_id, 
      line_id, 
      sire_animal_id, 
      dam_animal_id, 
      dam_animal_id AS generic_id 
     FROM animals) 
SELECT CONNECT_BY_ROOT animal_id "ORIGINAL_ANIMAL", 
     animal_id, 
     line_id, 
     sire_animal_id, 
     dam_animal_id, 
     LEVEL - 1 "LEVEL" 
    FROM ani 
START WITH animal_id = '2360000002558' 
CONNECT BY (PRIOR generic_id = animal_id AND LEVEL < 5) 
Смежные вопросы