2010-10-13 20 views
2

Je l'instruction SQL suivante:Oracle 10g Connect En Avant - problèmes de performances

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)) 

Ceci dans un tableau avec environ 1,6 million d'animaux. Chaque enregistrement a Animal_Id, Sire_Animal_Id et Dam_Animal_Id (Sire = Père, Dam = Mère). J'utilise ce sql pour afficher le pedigree complet de l'animal. Les résultats montreront Animal, 2 Parent, 4 GrandParents, etc.

Mon problème est que cette déclaration prend 15 secondes, pour un animal. Il doit y avoir un moyen d'optimiser cela. Des pensées?

+6

Quel est le plan d'exécution? Quels index existent sur la table? –

+0

Il se peut que vous ayez ce OU dans la connexion (mêlant deux arbres dans une structure), avez-vous essayé une union de deux requêtes séparées (une pour l'arborescence, l'autre pour l'arbre de la damier)? – kurosch

Répondre

0

Existe-t-il des index sur sire_animal_id et dam_animal_id? Il peut être en train de faire des analyses de table complètes.

0

Oui, il existe des index.

0

J'ai essayé de recréer votre situation et je n'ai pas réussi à faire en sorte que Oracle utilise judicieusement les index. Je suis sûr qu'il y a une façon intelligente de le faire. Mais si personne d'autre ici ne peut le comprendre, voici la manière laide et laide.

Puisque vous n'obtenez qu'un certain nombre de niveaux, vous pouvez créer manuellement une connexion. Obtenir le premier niveau, l'union au second niveau (qui obtient les résultats d'une copie de la première requête), l'union au troisième niveau (qui obtient les résultats d'une copie de la deuxième requête), etc. Je n'ai fait que trois niveaux ici, mais vous pouvez copier et coller pour faire le quatrième. Il est plus difficile à utiliser car l'identifiant d'origine est répété tant de fois, mais il est super rapide (0,005 seconde sur ma machine avec 1,6 millions de disques.)

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

Je n'ai pas eu beaucoup de temps pour tester ce donc là est un peu de DYOR dans la réponse mais utiliserait une aide en ligne? Comme vous n'avez pas posté de plan d'explication, je ne peux pas vous en dire trop, et dans la solution ci-dessous, vous trouverez peut-être que l'union dans la clause WITH vous cause des problèmes de performances, mais cela peut vous aider. votre chemin vers une solution.

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)