Выполнение запроса очень плохое - PullRequest
3 голосов
/ 24 января 2012

У меня есть запрос ниже:

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 ]

3 голосов
/ 24 января 2012

Я бы хотел сделать следующее:

  1. рефакторинг для использования синтаксиса соединения ANSI для здравомыслия любого, кто придет после вас
  2. рефакторинг для устранения необходимости подзапроса в предложении WHERE, как это нужно будет выполнить по одному для каждой строки в таблице, а не только 10, которые вы возвращаете.
  3. если вы знаете вам понадобится только 10 строк, вы можете попробовать добавить подсказку /*+ FIRST_ROWS(10) */, чтобы дать Oracle оптимизатор руку помощи.
  4. нужна ли сортировка? Похоже, большая часть вашей работы выполнена здесь.
1 голос
/ 24 января 2012

Я предлагаю заменить предложение 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 будет внутренним объединением, поскольку вас интересуют только элементы, заказанные пользователями из компаний Dell Computer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...