【问题标题】:Oracle 10g Connect By Prior - Performance IssuesOracle 10g Connect By Prior - 性能问题
【发布时间】:2011-04-25 02:47:15
【问题描述】:

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

【问题讨论】:

  • 执行计划是什么?表上有哪些索引?
  • sire_animal_id 和 dam_animal_id 上是否有索引?它可能正在执行全表扫描。
  • 是的,有索引。
  • 这可能是您在连接中通过(在一个结构中混合两棵树)获得了 OR,您是否尝试过两个单独查询的联合(一个用于父系树,第二个用于大坝树)?

标签: sql oracle plsql oracle10g hierarchical-query


【解决方案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')
);

【讨论】:

    【解决方案2】:

    我没有很长时间对此进行测试,所以答案中有一点 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 )
    

    【讨论】:

      猜你喜欢
      • 2010-10-31
      • 2019-10-07
      • 1970-01-01
      • 2013-10-24
      • 2017-07-10
      • 2023-03-07
      • 1970-01-01
      • 2018-01-24
      • 1970-01-01
      相关资源
      最近更新 更多