Как я могу оптимизировать этот запрос, заняв 30 секунд для 1746 строк? - PullRequest
2 голосов
/ 12 июля 2010

Запрос:

SELECT A.USER_ID, A.ROLE_ID, C.SUBGROUP, MAX(A.STATUS_ID)
                 FROM USER_ROLE A, USER B, ROLE C
                WHERE A.ROLE_ID = C.ROLE_ID
                  AND C.GROUP_ID = 3
                  AND A.USER_ID = B.USER_ID
                  AND B.TEMPLATE_IND = 'N'
                  AND B.ONAP_PARTCODE IS NULL
                  AND A.PARTCODE ='005'
                GROUP BY A.PARTCODE,
                         A.USER_ID,
                         A.ROLE_ID,
                         C.SUBGROUP;

Объяснить план:

--------------------------------------------------------------------------------
| Id  | Operation                      | Name               | Rows  | Bytes | Co
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                    |     1 |    74 |
|   1 |  HASH GROUP BY                 |                    |     1 |    74 |
|   2 |   NESTED LOOPS                 |                    |     1 |    74 |
|   3 |    NESTED LOOPS                |                    |    56 |  3024 |
|   4 |     TABLE ACCESS BY INDEX ROWID| ROLE               |     8 |   240 |
|*  5 |      INDEX RANGE SCAN          | N_ROLE_IDX2        |     8 |       |
|   6 |     TABLE ACCESS BY INDEX ROWID| USER_ROLE          |     7 |   168 |
|*  7 |      INDEX RANGE SCAN          | N_USER_ROLE_IDX6   |     7 |       |
|   8 |    REMOTE                      | MV_PT_USER         |     1 |    20 |
--------------------------------------------------------------------------------

Ответы [ 5 ]

4 голосов
/ 12 июля 2010

Я переписал ваш запрос, чтобы использовать синтаксис ANSI-92:

  SELECT A.USER_ID, A.ROLE_ID, C.SUBGROUP, MAX(A.STATUS_ID)
    FROM USER_ROLE a
    JOIN USER b ON b.user_id = a.user_id
               AND b.template_ind = 'N'
               AND b.onap_partcode IS NULL
    JOIN ROLE c ON c.role_id = a.role_id
               AND c.group_id = 3
   WHERE a.PARTCODE ='005'
GROUP BY a.USER_ID, a.ROLE_ID, c.SUBGROUP, a.PARTCODE;

Это не так быстро, просто мне яснее предложить следующие индексы покрытия :

CREATE INDEX ur_idx ON USER_ROLE (user_id, role_id, partcode) COMPUTE STATISTICS;
CREATE INDEX u_idx ON USER (user_id, template_ind) COMPUTE STATISTICS;
CREATE INDEX r_idx ON ROLE (role_id, group_id) COMPUTE STATISTICS;
2 голосов
/ 12 июля 2010

Оценка ROWS в плане заканчивается 1, а не около 1700. «Удаленная» операция на MV_PT_USER интересна. Похоже, что оптимизатор предполагает, что одна (или, возможно, ноль) строка будет возвращена этой операцией, даже если фильтрация отсутствует.

Сбор некоторой статистики по этому объекту может сказать oracle, сколько строк он может вернуть, и предложить оптимизатору другой план.

0 голосов
/ 27 сентября 2012

Я думаю, вам лучше изучить, что такое внутреннее соединение, правое соединение и левое соединение

Если у всей таблицы есть общее поле, а не ноль, то вы можете рассмотреть внутреннее соединение, которое имеет дело с наименьшим числом строк

0 голосов
/ 12 июля 2010

Ваш запрос занимает 30 секунд.Теперь нам нужно знать, на что тратятся эти 30 секунд.Предоставленная информация почти ничего не дает, поэтому пришло время отследить выполнение запроса.

Вот краткая информация о том, как собрать необходимую информацию: http://forums.oracle.com/forums/thread.jspa?messageID=1812597

С уважением, Роб.

0 голосов
/ 12 июля 2010

Не зная подробностей о вашей схеме таблицы и индексах, было бы трудно дать достойный совет.

Вероятно, это не очень поможет, но я вижу, что A.PARTCODE в вашем предложении GROUP BY не нужен.

...