我有以下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秒。必须有一种方法来优化这一点。有什么想法吗?
答案 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 )