Oracle 11g中的WITH Clause性能问题

时间:2017-10-15 09:29:28

标签: oracle performance oracle11g query-optimization database-performance

表myfirst3有4列和120万条记录。

表mtl_object_genealogy有超过1000万条记录。

运行以下代码需要很长时间。如何使用选项调整此代码?

WITH level1 as ( 
    SELECT  mln_parent.lot_number, 
            mln_parent.inventory_item_id,
            gen.lot_num ,--fg_lot, 
            gen.segment1,
            gen.rcv_date.
    FROM mtl_lot_numbers mln_parent,
          (SELECT   MOG1.parent_object_id,
                    p.segment1,
                    p.lot_num,
                    p.rcv_date
            FROM mtl_object_genealogy MOG1 ,
                 myfirst3 p
            START WITH MOG1.object_id = p.gen_object_id
            AND (MOG1.end_date_active IS NULL OR MOG1.end_date_active > SYSDATE)
            CONNECT BY nocycle PRIOR MOG1.parent_object_id = MOG1.object_id
            AND (MOG1.end_date_active IS NULL  OR MOG1.end_date_active > SYSDATE)
            UNION all
            SELECT p1.gen_object_id,
                   p1.segment1,
                   p1.lot_num,
                   p1.rcv_date 
            FROM myfirst3 p1 ) gen
    WHERE mln_parent.gen_object_id = gen.parent_object_id )
select /*+ NO_CPU_COSTING */ * 
from level1;

执行计划

enter image description here

CREATE TABLE APPS.MYFIRST3
(
  TO_ORGANIZATION_ID    NUMBER,
  LOT_NUM               VARCHAR2(80 BYTE),
  ITEM_ID               NUMBER,
  FROM_ORGANIZATION_ID  NUMBER,
  GEN_OBJECT_ID         NUMBER,
  SEGMENT1              VARCHAR2(40 BYTE),
  RCV_DATE              DATE
);

CREATE TABLE INV.MTL_OBJECT_GENEALOGY
(
  OBJECT_ID               NUMBER                NOT NULL,
  OBJECT_TYPE             NUMBER                NOT NULL,
  PARENT_OBJECT_ID        NUMBER                NOT NULL,
   START_DATE_ACTIVE       DATE                  NOT NULL,
  END_DATE_ACTIVE         DATE,
  GENEALOGY_ORIGIN        NUMBER,
  ORIGIN_TXN_ID           NUMBER,
  GENEALOGY_TYPE          NUMBER,
  );

CREATE INDEX INV.MTL_OBJECT_GENEALOGY_N1 ON INV.MTL_OBJECT_GENEALOGY(OBJECT_ID);

CREATE INDEX INV.MTL_OBJECT_GENEALOGY_N2 ON INV.MTL_OBJECT_GENEALOGY(PARENT_OBJECT_ID);

1 个答案:

答案 0 :(得分:0)

你的解释计划显示了一些非常大的数字。优化器估计最终结果集大约为3227,000,000,000行。只返回那么多行需要一些时间。

所有表访问都是全表扫描。因为你有大桌子也会花时间。

至于改进,我们很难理解查询的逻辑。这是您的数据模型,业务规则和数据。你还没有解释任何事情,所以我们所能做的就是猜测。

为什么使用WITH子句?您只使用level结果集一次,因此只需要一个常规的FROM子句。

你为什么要使用UNION ALL?该操作只会复制从myfirst3检索到的记录(所有这些值都已包含在MOG1.object_id = p.gen_object_id的行中。

MERGE JOIN CARTESIAN操作非常有趣。 Oracle使用它来实现传递闭包。这是一项昂贵的操作,但这是因为树木层次结构是一件昂贵的事情。不幸的是,您正在为具有2700万条记录的表生成所有父子关系。那很糟糕。

全表扫描不是问题所在。 myfirst3上没有过滤器,所以显然数据库必须获取所有记录。如果每个myfirst3记录都有一个父级,其中10%的内容为mtl_object_genealogy,那么全表扫描效率会很高;但是你要整个层次结构卷起来,所以它就像你在看着更大的一块桌子。

面对这些数字,您的索引无关紧要。可能有帮助的是mtl_object_genealogy(OBJECT_ID, PARENT_OBJECT_ID, END_DATE_ACTIVE)上的综合索引。

您希望myfirst3中记录的所有级别的PARENT_OBJECT_ID。如果您经常运行此查询并且mtl_object_genealogy是一个缓慢变化的表,您应该考虑将传递闭包实现到一个表中,该表只包含叶记录和父项的所有排列的记录。

总结一下:

  1. 抛弃WITH子句
  2. 放弃UNION ALL
  3. 使用复合索引调整树行走(或实现它)