4

我有以下 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 来显示完整的动物谱系。结果将显示动物、2 个父母、4 个祖父母等。

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

4

2 回答 2

1

我没有很长时间来测试这个,所以答案中有一点 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 )
于 2011-07-15T15:36:43.730 回答
1

我尝试重现您的情况,但无法让 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')
);
于 2010-10-15T06:40:02.457 回答