2010-06-28 3 views
1

Je passe par un certain code pl/sql sans commentaires. Essayer de donner un sens à cela et de l'optimiser. Voici l'exemple:Comment puis-je optimiser ces ensembles de requêtes Oracle

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; 

Puis

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 
        ) 
       ) 
       ); 

enfin (ce qui prend le plus long)

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; 

Y at-il une manière que je peux éviter la suppression de gtt1 et d'abord simplement obtenir des lignes nous vouloir?

Exécution expliquer le plan je constate des analyses complètes de table sur cette requête:

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 lignes

cmp_role = 27 lignes

user_role a 5 indices:

idx 1 = rôle_id

idx 2 = last_updt_user_id

idx 3 = actv_id, participant_code, effective_from_Date, effective_to_date

idx 4 = user_id, role_id, effective_from_Date, effective_to_date

idx 5 = participant_code, user_id, roke_id, actv_cd

+0

Est-ce que gtt1 est toujours le même dans vos requêtes? Sont-ils des requêtes séquentielles? Peut-être que vous pourriez essayer de les écrire dans une seule requête au lieu de trois? –

Répondre

0

L'INSERT et SUPPR me paraissent être équivalent à ceci:

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 
           )) 
          ); 

Que ce soit plus efficace, je ne sais pas - J'aurais besoin d'en savoir beaucoup plus sur les tables, les index et les données.

Vous pouvez alors aller plus loin et tourner le GTT dans un sous-requête, par exemple:

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; 

Encore une fois, je ne sais pas si cela est plus ou moins efficace que le code actuel.

+0

Tony, la requête combinée WITH WITH' fonctionne parfaitement, mais j'ai encore besoin de me raser un peu de temps. Je fournis les lignes dans toutes les tables. pourriez-vous s'il vous plaît voir si cela peut être optimisé quelque part? – Mehur

+0

Je ne suis pas surpris que la requête implique des analyses complètes: cmp_role n'a que 27 lignes, donc un scan complet a du sens, et un scan complet sur user_role PEUT aussi avoir du sens si beaucoup de ses lignes correspondent au critère participant_code null et group_id = 3 (combien de lignes user_role répondent-elles à ces critères?) –

+0

39392 lignes sont renvoyées lors de l'exécution de cette requête et cela prend 19 secondes. – Mehur

1

Voulez-vous optimiser la requête elle-même ou simplement le temps qu'il faut pour donner les résultats? deuxième aurait besoin des données sur le nombre de lignes et ainsi de suite ...

+0

juste le temps qu'il faut pour les résultats. Je vais fournir plus de détails sur le nombre de lignes pour chaque table utilisée. – Mehur

Questions connexes