Oracle 10g按优先级连接 - 性能问题

时间:2010-10-13 22:15:01

标签: sql oracle plsql oracle10g hierarchical-query

我有以下SQL语句:

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

这张表中有大约160万只动物。每条记录都有Animal_Id,Sire_Animal_Id和Dam_Animal_Id(Sire =父亲,Dam =母亲)。

我使用这个sql来显示完整的动物血统。结果将显示Animal,2 Parent,4 GrandParents等

我的问题是,对于一只动物,这句话需要15秒。必须有一种方法来优化这一点。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我尝试重新创建您的情况,但我无法让Oracle明智地使用这些索引。我确信有一些聪明的方法可以做到这一点。但如果这里没有其他人可以弄清楚,下面是愚蠢,丑陋的方式。

由于您只获得了一定数量的级别,因此您可以手动创建连接。获得第一级,第二级联合(从第一个查询的副本获得结果),联合到第三级(从第二个查询的副本获得结果)等等。我只做了三个级别在这里,但您可以复制并粘贴以制作第四个。由于原始id重复了很多次,所以使用起来比较困难,但速度非常快(我的机器上有0.005秒,有160万条记录。)

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

答案 1 :(得分: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 )