How can I optimize an sql query!

-1

Hello good afternoon friends, I hope and are well, I was asked at work to work on this query:

SELECT
  CAST(cd_ITVALCNV AS VARCHAR(6)) AS cd_ITVALCNV,
  cd_ICTTO,
  CAST(cd_IEMISORA AS VARCHAR(8)) AS cd_IEMISORA,
  CAST(cd_ISERIE AS   VARCHAR(8)) AS cd_ISERIE,
  cd_ICUPON,
  cd_ISUBFOL,
  cd_IFOLADM,
  CAST(nb_SORIMOV AS VARCHAR(2)) AS nb_SORIMOV,
  cd_FOPERA,
  im_CTITEXI
FROM
  (
    SELECT
      cd_ITVALCNV,
      cd_ICTTO,
      cd_IEMISORA,
      cd_ISERIE,
      cd_ICUPON,
      cd_ISUBFOL,
      cd_IFOLADM,
      nb_SORIMOV,
      FN_MAXFOPERA(cd_ITVALCNV, cd_ICTTO, cd_IEMISORA, cd_ISERIE, cd_ICUPON,
      cd_ISUBFOL, cd_IFOLADM, nb_SORIMOV) AS cd_FOPERA,
      FN_LASTCTITEXI(cd_ITVALCNV, cd_ICTTO, cd_IEMISORA, cd_ISERIE, cd_ICUPON,
      cd_ISUBFOL, cd_IFOLADM, nb_SORIMOV, FN_MAXFOPERA(cd_ITVALCNV, cd_ICTTO,
      cd_IEMISORA, cd_ISERIE, cd_ICUPON, cd_ISUBFOL, cd_IFOLADM, nb_SORIMOV))
      AS im_CTITEXI
    FROM
      (
        SELECT DISTINCT
          cd_ITVALCNV,
          cd_ICTTO,
          cd_IEMISORA,
          cd_ISERIE,
          cd_ICUPON,
          cd_ISUBFOL,
          CASE
            WHEN nb_SORIMOV = 'RP'
            THEN FN_MAXIFOLADM(cd_ITVALCNV, cd_ICTTO, cd_IEMISORA, cd_ISERIE,
              cd_ICUPON, cd_ISUBFOL, nb_SORIMOV)
            ELSE cd_IFOLADM
          END AS cd_IFOLADM,
          nb_SORIMOV
        FROM
          TVIV023_KARCAS KC
        WHERE
          cd_ISUBFOL <> 4
      )
  )
WHERE
  im_CTITEXI <> 0

This query depends on three functions that are:

1)

create or replace 
FUNCTION FN_LASTCTITEXI (V_itvalcnv IN CHAR,
                                V_ictto    IN NUMBER,
                                V_iemisora IN CHAR,
                                V_iserie   IN CHAR,
                                V_icupon   IN NUMBER,
                                V_isubfol  IN NUMBER,
                                V_ifoladm  IN NUMBER,
                                V_sorimov  IN CHAR,
                                V_fopera   IN VARCHAR2)
RETURN FLOAT IS
v_ctitexi FLOAT;
BEGIN
  SELECT im_CTITEXI
  INTO v_ctitexi
  FROM (SELECT ROWNUM AS id_ctitexi,
               im_CTITEXI
         FROM TVIV023_KARCAS 
         WHERE cd_ITVALCNV = V_itvalcnv
           AND cd_ICTTO    = V_ictto
           AND cd_IEMISORA = V_iemisora
           AND cd_ISERIE   = V_iserie
           AND cd_ICUPON   = V_icupon
           AND cd_ISUBFOL  = V_isubfol
           AND cd_IFOLADM  = V_ifoladm
           AND nb_SORIMOV  = V_sorimov
           AND cd_FOPERA   = V_fopera
         ORDER BY 1 DESC)
  WHERE ROWNUM = 1;
  RETURN v_ctitexi;
END;

2)

create or replace 
FUNCTION FN_MAXFOPERA (V_itvalcnv IN CHAR,
                              V_ictto    IN NUMBER,
                              V_iemisora IN CHAR,
                              V_iserie   IN CHAR,
                              V_icupon   IN NUMBER,
                              V_isubfol  IN NUMBER,
                              V_ifoladm  IN NUMBER,
                              V_sorimov  IN CHAR)
RETURN VARCHAR2 IS
v_fopera TVIV023_KARCAS.cd_FOPERA%TYPE;
BEGIN
  SELECT Max(cd_FOPERA)
  INTO v_fopera
  FROM TVIV023_KARCAS K
  WHERE K.cd_ITVALCNV = V_itvalcnv 
    AND K.cd_ICTTO    = V_ictto    
    AND K.cd_IEMISORA = V_iemisora 
    AND K.cd_ISERIE   = V_iserie   
    AND K.cd_ICUPON   = V_icupon   
    AND K.cd_ISUBFOL  = V_isubfol
    AND K.cd_IFOLADM  = V_ifoladm
    AND K.nb_SORIMOV  = V_sorimov;
  RETURN v_fopera;
END;

3)

create or replace 
FUNCTION FN_MAXIFOLADM (V_itvalcnv IN CHAR,
                               V_ictto    IN NUMBER,
                               V_iemisora IN CHAR,
                               V_iserie   IN CHAR,
                               V_icupon   IN NUMBER,
                               V_isubfol  IN NUMBER,
                               V_sorimov  IN CHAR)
RETURN NUMBER IS
v_ifoladm NUMBER;
BEGIN
  SELECT Max(cd_IFOLADM)
  INTO v_ifoladm
  FROM TVIV023_KARCAS K
  WHERE K.cd_ITVALCNV = V_itvalcnv 
    AND K.cd_ICTTO    = V_ictto    
    AND K.cd_IEMISORA = V_iemisora 
    AND K.cd_ISERIE   = V_iserie   
    AND K.cd_ICUPON   = V_icupon   
    AND K.cd_ISUBFOL  = V_isubfol  
    AND K.nb_SORIMOV  = V_sorimov  
    AND K.cd_FREG     = (SELECT Max(cd_FREG)
                         FROM TVIV023_KARCAS D
                         WHERE D.cd_ITVALCNV = V_itvalcnv 
                           AND D.cd_ICTTO    = V_ictto    
                           AND D.cd_IEMISORA = V_iemisora 
                           AND D.cd_ISERIE   = V_iserie   
                           AND D.cd_ICUPON   = V_icupon   
                           AND D.cd_ISUBFOL  = V_isubfol  
                           AND D.nb_SORIMOV  = V_sorimov);
  RETURN v_ifoladm;
END;

The problem is that it takes too long to finish the query, I wanted to know if you can help me in providing me with suggestions on how to optimize the query without modifying the sentences if possible, I do not really know much about the database, but I They give suggestions of how to solve this problem I would be very grateful, I remain on the side of friends, greetings and excellent afternoon.

Note: Only one table is used and already probe with using indexes and doing everything locally creating the table and doing the functions but still can not.

In the execution plan he throws this at me:

Practically the indices do not take them into account and assign it in this field cd_ISUBFO and the example that I sent from a user who does not have privileges to add indexes,

OF RECORDS ARE: 48582

Another thing is that for the same reason that it takes a long time I do not know exactly how much, what I have seen is takes more than 1 hour and so it continues. : (

    
asked by JUAN JOSE BUSTAMANTE SOLIS 06.03.2018 в 23:40
source

2 answers

4

First of all understand that everything I put in is indicative because I can not run tests to know the performance, but perhaps it will serve as a guide.

The main reason for your high times is that you are executing many (too many) subselects , both in the original select, which you have subdivided into 3, and in each of the functions that You are calling throughout the code and some of them go inside other functions. At the end you have the program going around the same table again and again when it would be logical to have at most a couple of subselects at most.

That's why I think to begin with, a good objective to achieve is that your query looks like something like this:

SELECT DISTINCT CAST(cd_ITVALCNV AS VARCHAR(6)) AS cd_ITVALCNV,
                CD_ICTTO,
                CAST(cd_IEMISORA AS VARCHAR(8)) AS cd_IEMISORA,
                CD_ISERIE,
                CD_ICUPON,
                CD_ISUBFIL,
                CASE
                  WHEN nb_SORIMOV = 'RP'
                  THEN FN_MAXIFOLADM(cd_ITVALCNV, cd_ICTTO, cd_IEMISORA, cd_ISERIE,
                    cd_ICUPON, cd_ISUBFOL, nb_SORIMOV)
                  ELSE cd_IFOLADM
                END AS cd_IFOLADM,
                CAST(nb_SORIMOV AS VARCHAR(2)) AS nb_SORIMOV,
                Max(cd_FOPERA) AS cd_FOPERA,
                im_CTITEXI AS im_CTITEXI
FROM TVI023_KARCAS KC
WHERE im_CTITEXI <> 0 AND cd_ISUBFOL <>4;

What I've done:

  • I condensed the 3 initial subqueries into 1 single.
  • I eliminate the function 2 called FN_MAXFOPERA that in the end all it does is bring Max (cd_FOPERA), which you can do directly in the query.

As you can see, all the code is condensed into a single query, so you optimize the execution times by not having a query that depends on another one that in turn depends on another.

With respect to the function 1 and 3 it is not very clear to me that you intend to achieve with them, because in the end you are matching the codes of all the columns in their respective where, which leaves you with the initial element that you intended to obtain.

Finally, and perhaps the key to solving the problem: Is it mandatory that everything is in a single query? In my opinion I think using a PROCEDURE and Segment the data calculation is the most convenient. Above all I would try to separate the functions of the main SELECT.

    
answered by 07.03.2018 в 01:25
0

What's up, my friends, here I am going to leave my two cents with the consultation already finished:

WITH max_cd_freg_t AS (
    SELECT
        cd_itvalcnv,
        cd_ictto,
        cd_iemisora,
        cd_iserie,
        cd_icupon,
        cd_isubfol,
        nb_sorimov,
        MAX(cd_freg) AS max_cd_freg
    FROM
        tviv023_karcas
    GROUP BY
        cd_itvalcnv,
        cd_ictto,
        cd_iemisora,
        cd_iserie,
        cd_icupon,
        cd_isubfol,
        nb_sorimov
),qdistinct AS (
    SELECT
        a.cd_itvalcnv,
        a.cd_ictto,
        a.cd_iemisora,
        a.cd_iserie,
        a.cd_icupon,
        a.cd_isubfol,
        a.nb_sorimov,
        a.cd_freg,
        MAX(cd_ifoladm) fn_maxifoladm
    FROM
        tviv023_karcas a
        JOIN max_cd_freg_t b ON a.cd_itvalcnv = b.cd_itvalcnv
                                AND a.cd_ictto = b.cd_ictto
                                AND a.cd_iemisora = b.cd_iemisora
                                AND a.cd_iserie = b.cd_iserie
                                AND a.cd_icupon = b.cd_icupon
                                AND a.cd_isubfol = b.cd_isubfol
                                AND a.nb_sorimov = b.nb_sorimov
                                AND a.cd_freg = b.max_cd_freg
    GROUP BY
        a.cd_itvalcnv,
        a.cd_ictto,
        a.cd_iemisora,
        a.cd_iserie,
        a.cd_icupon,
        a.cd_isubfol,
        a.nb_sorimov,
        a.cd_freg
),select_fnmaxfopera AS (
    SELECT DISTINCT
        kc.cd_itvalcnv,
        kc.cd_ictto,
        kc.cd_iemisora,
        kc.cd_iserie,
        kc.cd_icupon,
        kc.cd_isubfol,
        CASE
                WHEN kc.nb_sorimov = 'RP' THEN c.fn_maxifoladm
                ELSE kc.cd_ifoladm
            END
        AS cd_ifoladm,
        kc.nb_sorimov
    FROM
        tviv023_karcas kc
        JOIN qdistinct c ON kc.cd_itvalcnv = c.cd_itvalcnv
                            AND kc.cd_ictto = c.cd_ictto
                            AND kc.cd_iemisora = c.cd_iemisora
                            AND kc.cd_iserie = c.cd_iserie
                            AND kc.cd_icupon = c.cd_icupon
                            AND kc.cd_isubfol = c.cd_isubfol
                            AND kc.nb_sorimov = c.nb_sorimov
    WHERE
        kc.cd_isubfol <> 4     
           --and kc.nb_sorimov <> 'RP'     
),select_fn_maxofopera AS (
    SELECT
        cd_itvalcnv,
        cd_ictto,
        cd_iemisora,
        cd_iserie,
        cd_icupon,
        cd_isubfol,
        cd_ifoladm,
        nb_sorimov,
        MAX(cd_fopera) AS fn_maxfopera
    FROM
        tviv023_karcas
    WHERE
        cd_isubfol <> 4
    GROUP BY
        cd_itvalcnv,
        cd_ictto,
        cd_iemisora,
        cd_iserie,
        cd_icupon,
        cd_isubfol,
        cd_ifoladm,
        nb_sorimov
    ORDER BY
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8
),union_distinct_y_maxofpera AS (
    SELECT
        v.cd_itvalcnv,
        v.cd_ictto,
        v.cd_iemisora,
        v.cd_iserie,
        v.cd_icupon,
        v.cd_isubfol,
        v.cd_ifoladm,
        v.nb_sorimov,
        v.fn_maxfopera AS cd_fopera,
        fn_lastctitexi(v.cd_itvalcnv,v.cd_ictto,v.cd_iemisora,v.cd_iserie,v.cd_icupon,v.cd_isubfol,v.cd_ifoladm,v.nb_sorimov,v.fn_maxfopera
) AS im_ctitexi
    FROM
        select_fnmaxfopera x
        JOIN select_fn_maxofopera v ON x.cd_itvalcnv = v.cd_itvalcnv
                                       AND x.cd_ictto = v.cd_ictto
                                       AND x.cd_iemisora = v.cd_iemisora
                                       AND x.cd_iserie = v.cd_iserie
                                       AND x.cd_icupon = v.cd_icupon
                                       AND x.cd_isubfol = v.cd_isubfol
                                       AND x.cd_ifoladm = v.cd_ifoladm
                                       AND x.nb_sorimov = v.nb_sorimov
) SELECT
    CAST(cd_itvalcnv AS VARCHAR(6) ) cd_itvalcnv,
    cd_ictto,
    CAST(cd_iemisora AS VARCHAR(8) ) cd_iemisora,
    CAST(cd_iserie AS VARCHAR(8) ) cd_iserie,
    cd_icupon,
    cd_isubfol,
    cd_ifoladm,
    CAST(nb_sorimov AS VARCHAR(2) ) AS nb_sorimov,
    cd_fopera,
    im_ctitexi
  FROM
    union_distinct_y_maxofpera
  WHERE
    im_ctitexi <> 0

Greetings and good vibes.

    
answered by 26.04.2018 в 16:50