查询的性能非常糟糕

时间:2012-01-24 06:14:29

标签: sql oracle11g

我有以下查询:

SELECT so1b.hasattachments,
       so1b.sorefitem,
       so1b.sonumber,
       so1b.custponumber,
       so1b.sodate,
       so1b.ostatus,
       so1b.osubstatus,
       so1b.urefitem,
       so1b.username,
       so1b.summary,
       so1b.purefitem
FROM (SELECT DECODE (COUNT (ATT.SOREFITEM), 0, 0, 1) hasattachments,
             so1.SOREFITEM,
             SONUMBER,
             CUSTPONUMBER,
             SODATE,
             so1.OSTATUS,
             so1.OSUBSTATUS,
             so1.urefitem AS urefitem,
             so1.username AS username ,
             ''           AS summary ,
             so1.PUREFITEM
      FROM  ECOrders.SALESORDERS so1,
            ECORDERS.ATTACHMENTS att,
            ecusers.ownership o
      WHERE att.SOREFITEM (+) =so1.SOREFITEM
        AND so1.UREFITEM        = o.urefitem
        AND o.uownerref         = ?
        AND so1.sorefitem      IN
            (SELECT ot.sorefitem
             FROM ECOrders.ORDERITEMS ot,
                  ECUSERS.USERINFO USI
             WHERE ot.sorefitem=so1.sorefitem
               AND OT.OSELLERID  = USI.UREFITEM (+)
               AND UPPER(USI.USERNAME) LIKE UPPER('%Dell Computer%') ESCAPE '~'
            )
      GROUP BY SO1.SOREFITEM,
            SONUMBER,
            CUSTPONUMBER,
            SODATE,
            so1.OSTATUS,
            so1.OSUBSTATUS,
            so1.UREFITEM,
            so1.USERNAME,
            so1.PUREFITEM
      ORDER BY SOREFITEM DESC /* sort is possible on all columns */
      ) so1b
WHERE rownum BETWEEN 1 AND 10

当数据很大时,此查询执行得非常糟糕。执行计划如下:

ID  PA_ID   Execution Plan                                                                      COST    CARD    BYTES
0       SELECT STATEMENT Optimizer=CHOOSE                                                       2906    10      9480
1   0   -COUNT (STOPKEY)             
2   1   --FILTER             
3   2   ---VIEW                                                                                 2906    381     361188
4   3   ----SORT (GROUP BY)                                                                     2906    381     32766
5   4   -----FILTER          
6   5   ------NESTED LOOPS (OUTER)                                                              18      2888    248368
7   6   -------NESTED LOOPS                                                                     17      2888    231040
8   7   --------TABLE ACCESS (BY INDEX ROWID) of 'ECUSERS.OWNERSHIP' (TABLE)                    1       24      240
9   8   ---------INDEX (RANGE SCAN) of 'ECUSERS.OWNERSHIP_UOWNERREF' (INDEX)                    1       24   
10  7   --------TABLE ACCESS (BY INDEX ROWID) of 'ECORDERS.SALESORDERS' (TABLE)                 1       121     8470
11  10  ---------INDEX (RANGE SCAN) of 'ECORDERS.SO_UREFITEM_OSTATUS_OSUB' (INDEX)              1       76   
12  6   -------INDEX (RANGE SCAN) of 'ECORDERS.ATTACHMENTS_SOREFITEM' (INDEX)                   1       1       6
13  5   ------NESTED LOOPS  2   1   49
14  13  -------TABLE ACCESS (BY INDEX ROWID) of 'ECORDERS.ORDERITEMS' (TABLE)                   1       3       33
15  14  --------INDEX (RANGE SCAN) of 'ECORDERS.ORDERITEMS_SOREFITEM02' (INDEX)                 1       3    
16  13  -------INDEX (RANGE SCAN) of 'ECUSERS.USERINFO_I_USERNAME_UREFITEM' (INDEX (UNIQUE))    1       1       38
ID  PA_ID   Execution Plan                                                                      COST    CARD    BYTES

有什么方法可以提高此查询的效果吗?

2 个答案:

答案 0 :(得分:3)

我希望做到以下几点:

  1. 重构use ANSI join syntax,为了你后面的任何人的理智
  2. 重构,以消除WHERE子句中对子查询的需要 将需要为表中的每一行执行一次,而不仅仅是 你带回来的那个。
  3. 如果你知道你只需要10 在行中,您可以尝试添加/*+ FIRST_ROWS(10) */提示来提供Oracle 优化者伸出援助之手。
  4. 是必要的吗?好像你的大部分工作都是在这里完成的。

答案 1 :(得分:1)

我建议用in子句替换exists子句 - 如下所示:

        AND exists
            (SELECT null
             FROM ECOrders.ORDERITEMS ot
             JOIN ECUSERS.USERINFO USI 
               on OT.OSELLERID  = USI.UREFITEM
              AND UPPER(USI.USERNAME) LIKE UPPER('%Dell Computer%') ESCAPE '~'
             WHERE ot.sorefitem=so1.sorefitem
            )

ORDERITEMS和USERINFO之间的联接将是一个内部联接,因为您只对戴尔计算机公司的用户订购的项目感兴趣。