Как я могу оптимизировать этот набор запросов оракула - PullRequest
1 голос
/ 28 июня 2010

Я прошёл какой-нибудь код pl / sql без комментариев. Попытка понять это и оптимизировать это. Вот образец:

INSERT INTO gtt1 --75711 rows
(USER_ID, role_id, participant_code, status_id )
SELECT
 r.user_id, r.role_id, r.participant_code, MAX(status_id)
FROM
  user_role r,
  cmp_role c
WHERE
  r.role_id = c.role_id
  AND r.participant_code IS NOT NULL
  AND c.group_id = 3
  GROUP BY
  r.user_id, r.role_id, r.participant_code;

Тогда

DELETE gtt1
WHERE ROWID IN (SELECT ROWID FROM gtt1
                MINUS
                SELECT a.ROWID FROM gtt1 a, UIV_CMP_USER_ROLE b
                WHERE a.status_id = b.status_id
                AND (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 ) 
                      AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
                     )
                )
                );

наконец (это занимает больше всего)

OPEN cv_1 FOR

SELECT c.role_id,
       c.subgroup,
       c.subgroup_description,
       COUNT(a.USER_ID) user_count
FROM   
    (SELECT b.user_id, b.role_id FROM gtt1 b, pt_user e
    --pt_user table has 73000 rows
        WHERE  e.user_id = RTRIM(b.user_id)
       ) a
RIGHT OUTER JOIN CMP_ROLE c ON a.role_id = c.role_id
WHERE c.group_id = v_group_id
GROUP BY c.role_id,c.subgroup,c.subgroup_description
ORDER BY c.subgroup;

Есть ли способ избежать удаления из gtt1 и просто получить нужные нам строки?

Запуск Объяснение плана Я заметил несколько полных сканирований таблицы по этому запросу:

SELECT 
   r.user_id, r.role_id, r.participant_code, MAX(status_id) 
  FROM 
    user_role r, 
    cmp_role c 
  WHERE 
    r.role_id = c.role_id 
    AND r.participant_code IS NOT NULL 
    AND c.group_id = 3 
    GROUP BY 
    r.user_id, r.role_id, r.participant_code 
    HAVING MAX(status_id) IN (SELECT b.status_id FROM UIV_CMP_USER_ROLE b 
                              WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )  
                                     AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date 
                                    )) 
                             ) 

user_role = 803507 строк

cmp_role = 27 строк

user_role имеет 5 индексов:

idx 1 = role_id

idx 2 = last_updt_user_id

idx 3 = actv_id, код участника, фактическая_дата_дата, эффективная_дата_дата

idx 4 = идентификатор_пользователя, идентификатор_ роли, эффективная_дата_даты, эффективная_дата_дата

idx 5 = код участника, идентификатор пользователя, roke_id, actv_cd

Ответы [ 2 ]

1 голос
/ 28 июня 2010

Хотите оптимизировать сам запрос или просто время, необходимое для получения результатов?Во-вторых, потребуются некоторые данные о количестве строк и т. Д. ...

0 голосов
/ 28 июня 2010

Мне кажется, что INSERT и DELETE эквивалентны этому:

INSERT INTO gtt1 --75711 rows
(USER_ID, role_id, participant_code, status_id )
SELECT
 r.user_id, r.role_id, r.participant_code, MAX(status_id)
FROM
  user_role r,
  cmp_role c
WHERE
  r.role_id = c.role_id
  AND r.participant_code IS NOT NULL
  AND c.group_id = 3
  GROUP BY
  r.user_id, r.role_id, r.participant_code
  HAVING MAX(status_id) IN (SELECT b.status_id FROM UIV_CMP_USER_ROLE b
                            WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 ) 
                                   AND SYSDATE BETWEEN b.effective_from_date
                                               AND b.effective_to_date
                                  ))
                           );

Является ли это более эффективным, я понятия не имею - мне нужно знать намного больше о таблицах, индексах и данных.

Затем вы можете пойти дальше и превратить GTT в подзапрос, например:

WITH gtt1 AS 
  (SELECT
   r.user_id, r.role_id, r.participant_code, MAX(status_id)
  FROM
    user_role r,
    cmp_role c
  WHERE
    r.role_id = c.role_id
    AND r.participant_code IS NOT NULL
    AND c.group_id = 3
    GROUP BY
    r.user_id, r.role_id, r.participant_code
    HAVING MAX(status_id) IN (SELECT b.status_id FROM UIV_CMP_USER_ROLE b
                              WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 ) 
                                     AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
                                    ))
                             )
  )
SELECT c.role_id,
       c.subgroup,
       c.subgroup_description,
       COUNT(a.USER_ID) user_count
FROM   
    (SELECT b.user_id, b.role_id FROM gtt1 b, pt_user e
    --pt_user table has 73000 rows
        WHERE  e.user_id = RTRIM(b.user_id)
       ) a
RIGHT OUTER JOIN CMP_ROLE c ON a.role_id = c.role_id
WHERE c.group_id = v_group_id
GROUP BY c.role_id,c.subgroup,c.subgroup_description
ORDER BY c.subgroup;

Опять же, я понятия не имею, является ли это более или менее эффективным, чем текущий код.

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