2017-10-06 5 views
2

J'ai problème de performance avec cette requête spécifique:Oracle 11g: optimisation des performances des requêtes

SELECT ID, 
     NAME, 
     CREATION_DATE, 
     MODIFICATION_DATE, 
     CREATION_USER, 
     MODIFICATION_USER, 
     CODE, 
     START_DATE, 
     TO_CHAR(ANSWER) AS ANSWER, 
     STATUS, 
     RESUME, 
     REQUIRED, 
     RTRIM(
     XMLAGG(
      XMLELEMENT(E,QW.WARD_ID,',').EXTRACT('//text()') 
      ORDER BY QW.WARD_ID 
     ).GetClobVal(), 
     ',' 
     ) AS wards 
FROM RD_QUESTIONS Q 
     LEFT JOIN RD_QUESTIONS_WARDS QW ON QW.QUESTION_ID = ID 
GROUP BY ID, 
     NAME, 
     CREATION_DATE, 
     MODIFICATION_DATE, 
     CREATION_USER, 
     MODIFICATION_USER, 
     CODE, 
     START_DATE, 
     TO_CHAR(ANSWER), 
     STATUS, 
     RESUME, 
     REQUIRED 

LDD

CREATE TABLE RD_QUESTIONS(
    ID NUMBER(38, 0), 
    NAME VARCHAR(255) NOT NULL, 
    CREATION_DATE TIMESTAMP(6), 
    MODIFICATION_DATE TIMESTAMP(6), 
    CREATION_USER VARCHAR(20), 
    MODIFICATION_USER VARCHAR(20), 
    SECTION_ID NUMBER(38, 0), 
    CHAPTER_ID NUMBER(38, 0), 

    CONSTRAINT RD_QUESTIONS_PK3 PRIMARY KEY (ID), 
); 

CREATE TABLE RD_QUESTIONS_WARDS(
    QUESTION_ID NUMBER(38, 0), 
    WARD_ID NUMBER(38, 0), 

    CONSTRAINT RD_QUESTIONS_WARDS_PK4 PRIMARY KEY (QUESTION_ID, WARD_ID), 
    CONSTRAINT RD_QUESTIONS_FK4 FOREIGN KEY (QUESTION_ID) REFERENCES RD_QUESTIONS(ID) 
); 

le problème est avec la déclaration RTRIM(XMLAGG(XMLELEMENT(E,WARD_ID,',').EXTRACT('//text()') ORDER BY WARD_ID).GetClobVal(),',') AS wards qui est vraiment lent à calculer. Le résultat que je recherche, est une colonne nommée "wards" avec tous les ids correspondants joints à une chaîne.

Quelqu'un avec une meilleure solution de performance?

+0

S'il vous plaît pouvez-vous donner le DDL pour les deux tables et modifier votre requête pour afficher quelle table les différentes colonnes appartiennent comme cela fera une énorme différence pour vos options . C'est à dire. Est-ce 'Q.WARD_ID' ou' QW.WARD_ID' (et similaire pour les autres colonnes) – MT0

Répondre

3

Vous pouvez déplacer l'agrégation dans une sous-requête afin que vous n'avez pas besoin de regrouper par toutes les colonnes de la table jointe:

SELECT Q.ID, 
     Q.NAME, 
     Q.CREATION_DATE, 
     Q.MODIFICATION_DATE, 
     Q.CREATION_USER, 
     Q.MODIFICATION_USER, 
     Q.CODE, 
     Q.START_DATE, 
     TO_CHAR(Q.ANSWER) AS ANSWER, 
     Q.STATUS, 
     Q.RESUME, 
     Q.REQUIRED, 
     QW.wards 
FROM RD_QUESTIONS Q 
     LEFT JOIN (
     SELECT Question_ID, 
       RTRIM(
        XMLAGG(
        XMLELEMENT(E,WARD_ID,',').EXTRACT('//text()') 
        ORDER BY WARD_ID 
       ).GetClobVal(), 
       ',' 
       ) AS wards 
     FROM RD_QUESTIONS_WARDS 
     GROUP BY QUESTION_ID 
     ) QW 
     ON QW.QUESTION_ID = Q.ID 

En outre, si la longueur de la chaîne WARD_ID agrégée ne va jamais être plus de 4000 caractères, vous pouvez utiliser LISTAGG:

FROM RD_QUESTIONS Q 
     LEFT JOIN (
     SELECT Question_ID, 
       LISTAGG(WARD_ID, ',') WITHIN GROUP (ORDER BY WARD_ID) AS wards 
     FROM RD_QUESTIONS_WARDS 
     GROUP BY QUESTION_ID 
     ) QW 
     ON QW.QUESTION_ID = Q.ID 
+0

LISTAGG a fait l'affaire, merci beaucoup. – Pietro