쿼리 실행 속도를 빠르게 하고 싶습니다. 0 8 3,165

by 이수달 [Oracle 기초] 쿼리속도 [2012.05.29 16:46:37]


안녕하세요.

최근 업무에서 필요한 쿼리를 작성중에, 결과값은 제대로 얻었지만 쿼리 실행 속도가 문제가 되서

여러가지로 수정작업을 하던중 한계를 느껴서 질문을 하게 되었습니다.

내용은 1년치의 골프장 매출현황을 필요에 맞게 가져오는것이구요.


================================================================================
  select
   substr(a.sale_date, 1, 6) as sale_date,
   NVL((SELECT COUNT(distinct(BOOK_DATE))
    FROM GBA01M WHERE CORP_CODE = '02' AND WORKGRP_CODE = '100' AND SUBSTR(BOOK_DATE, 1, 6) = SUBSTR(A.SALE_DATE, 1, 6) GROUP BY SUBSTR(BOOK_DATE, 1, 6)),0) AS GOLFDAY_CNT,
   nvl(max(b.member_count),0) as member_count,
  (select
   to_char(nvl(sum(case hole_code
        when '001' then 0.5
        else 1
       end), 0), '999,990.0')
   from gba01m gm
   where corp_code = a.corp_code
   and workgrp_code = '100'
   and 1 = (select item1
     from coz10s
     where gm.corp_code = corp_code
     and head = 'RS511'
     and detail = gm.cose
     and use_yn = 'Y')
   and book_date like SUBSTR(A.SALE_DATE, 1, 6) || '%') as member_team,
   nvl(max(b.member_front),0) as member_front,
   NVL(b.member_lent,0) + NVL(e.cart, 0) - (round(NVL(b.member_lent, 0) / 1.1*0.1) + round(NVL(e.cart, 0) / 1.1*0.1)) as member_lent,
   nvl(sum(decode(a.upjang_code, '1102', net_amt)), 0) as member_club_house,
   nvl(sum(decode(a.upjang_code, '1106', net_amt)), 0) as member_st_club_house,
   nvl(sum(decode(a.upjang_code, '1103', net_amt)), 0) as member_west_th,
   nvl(sum(decode(a.upjang_code, '1104', net_amt)), 0) as member_center_th,
   nvl(max(c.guest_count),0) as guest_count,
   (select
   to_char(nvl(sum(case hole_code
        when '001' then 0.5
        else 1
       end), 0), '999,990.0')
   from gba01m gm
   where corp_code = a.corp_code
   and workgrp_code = '100'
   and 2 = (select item1
     from coz10s
     where gm.corp_code = corp_code
     and head = 'RS511'
     and detail = gm.cose
     and use_yn = 'Y')
   and book_date like SUBSTR(A.SALE_DATE, 1, 6) || '%') as guest_team,
   nvl(max(c.guest_front),0) as guest_front,
   NVL(c.guest_lent,0) + NVL(e.n_cart, 0) - (round(NVL(c.guest_lent, 0) / 1.1*0.1) + round(NVL(e.n_cart, 0) / 1.1*0.1)) as guest_lent,
   nvl(sum(decode(a.upjang_code, '1105', net_amt)), 0) as guest_east_th,
   nvl(sum(decode(a.upjang_code, '1191', net_amt)), 0) as pro_shop,
   nvl(sum(decode(a.upjang_code, '1192', net_amt)), 0) as emp_res,
   nvl(sum(decode(a.upjang_code, '1199', net_amt)), 0) as etc_upjang,
   nvl(sum(decode(substr(a.upjang_code, 1, 1), '1', net_amt)), 0) as golf_sum,
   nvl(sum(net_amt), 0) as resort_sum,
   NVL(D.LAST_GOLFSUM,0) AS LAST_GOLFSUM,
   NVL(D.LAST_RESORTAMT,0) AS LAST_RESORTAMT,
   DECODE(NVL(D.LAST_GOLFSUM,0),0,0,ROUND(NVL(SUM(DECODE(SUBSTR(A.UPJANG_CODE,1,1), '1', NET_AMT)),0)*100/NVL(D.LAST_GOLFSUM,0)-100,0)) AS GOLF_COMPARE,
   DECODE(NVL(D.LAST_RESORTAMT,0),0,0,ROUND(NVL(SUM(NET_AMT),0)*100/NVL(D.LAST_RESORTAMT,0)-100,0)) AS RESORT_COMPARE
 from baa07s a,
  (select
   SUBSTR(gd.BOOK_DATE, 1, 6) as book_date,
   to_char(nvl(sum(case gm.hole_code
        when '001' then 0.5
        else 1
       end), 0), '999,990.0') as member_count,
    sum(gd.ENTR_FEE) as member_front,
    sum(gd.LENT_FEE) as member_lent
   from gba01d gd, gba01m gm
   where gd.corp_code = gm.corp_code
   and gd.workgrp_code = gm.workgrp_code
   and gd.book_date = gm.book_date
   and gd.cose   = gm.cose
   and 1 = (select item1
     from coz10s
     where gd.corp_code = corp_code
     and head = 'RS511'
     and detail = gd.cose
     and use_yn = 'Y')
   and gd.time   = gm.time
   and gd.corp_code = '02'
   and gd.workgrp_code = '100'
   and gd.del_yn  = 'N'
   and gd.BOOK_DATE LIKE '2012' || '%'
   group by SUBSTR(gd.BOOK_DATE, 1, 6)) b,
  (select
   SUBSTR(gd.BOOK_DATE, 1, 6) as book_date,
   to_char(nvl(sum(case gm.hole_code
        when '001' then 0.5
        else 1
       end), 0), '999,990.0') as guest_count,
   sum(gd.ENTR_FEE) as guest_front,
   sum(gd.LENT_FEE) as guest_lent
   from gba01d gd, gba01m gm
   where gd.corp_code = gm.corp_code
   and gd.workgrp_code = gm.workgrp_code
   and gd.book_date = gm.book_date
   and gd.cose   = gm.cose
   and 2 = (select item1
     from coz10s
     where gd.corp_code = corp_code
     and head = 'RS511'
     and detail = gd.cose
     and use_yn = 'Y')
   and gd.time   = gm.time
   and gd.corp_code = '02'
   and gd.workgrp_code = '100'
   and gd.del_yn  = 'N'
   and gd.BOOK_DATE LIKE '2012' || '%'
   group by SUBSTR(gd.BOOK_DATE, 1, 6)) c,
   (SELECT
    MAX(TO_CHAR(ADD_MONTHS(TO_DATE(SALE_DATE, 'YYYYMMDD'), 12), 'YYYYMM')) AS SALE_MON,
    NVL(SUM(DECODE(SUBSTR(UPJANG_CODE,1,1), '1', NET_AMT)),0) AS LAST_GOLFSUM,
    NVL(SUM(NET_AMT),0) AS LAST_RESORTAMT
   FROM BAA07S
   WHERE CORP_CODE = '02'
    AND SALE_DATE LIKE '2012' - 1|| '%'
    GROUP BY SUBSTR(SALE_DATE, 1, 6)
   ) d,
   (select SUBSTR(BOOK_DATE, 1, 6) as book_date,
     sum(decode(cose, '007', 0, CART_FEE)) as cart,
     sum(decode(cose, '007', CART_FEE, 0)) as n_cart
   from gbc03s
   where corp_code = '02'
   and WORKGRP_CODE = '100'
   and BOOK_DATE LIKE '2012' || '%'
   group by SUBSTR(BOOK_DATE, 1, 6)) e
 where a.corp_code = '02'
 and SUBSTR(a.sale_date, 1, 6) = b.book_date(+)
 and SUBSTR(a.sale_date, 1, 6) = c.book_date(+)
 and SUBSTR(A.SALE_DATE, 1, 6) = d.SALE_MON(+)
 and SUBSTR(a.sale_date, 1, 6) = e.book_date(+)
 and a.sale_date LIKE '2012' || '%'
 group by a.corp_code, SUBSTR(a.SALE_DATE, 1, 6), b.member_lent, c.guest_lent, e.cart, e.n_cart, d.LAST_GOLFSUM, d.LAST_RESORTAMT
 order by SUBSTR(A.SALE_DATE, 1, 6)


===============================================================================
쿼리문은 위와 같습니다.

오라클을 다룬지 얼마안된 초보라서 어설픈 쿼리문이지만,
검색 속도를 올릴 수 있는 팁이나, 그외 조언을 주시면 고맙겠습니다.
by 달빛아우림 [2012.05.29 19:21:01]
실행 계획도 없고 그냥 짐작으로 찍음

  1. and 1 = (select item1
  2.      from coz10s
  3.      where gd.corp_code = corp_code
  4.      and head = 'RS511'
  5.      and detail = gd.cose
  6.      and use_yn = 'Y')
  1. and 2 = (select item1
    1.         from coz10s 
    2.         where gd.corp_code = corp_code
    3.         and head = 'RS511'
    4.         and detail = gd.cose
    5.         and use_yn = 'Y')
    이 부분들이 많은 연산이 들어 갈것으로 예상되고요(찍었음)
    select 절은 이전에 group by 한번 해줘서 인라인뷰 만들어 연산을 한번 줄여 보도록 해보시고

    from 절은 위 부분을
    1. AND (gd.corp_code, gd.cose) IN(
    2. SELECT corp_code, cose
    3. FROM coz10s 
    4. WHERE head = 'RS511'  AND use_yn = 'Y' AND item1 = 1)
    이렇게 바꿔 보는건 어떼요? 단 이때 조건은
    1. SELECT corp_code, cose 
    2. FROM coz10s 
    3. WHERE head = 'RS511'  AND use_yn = 'Y' AND item1 = 1
    의 로우수가 많지 않을때

    쿼리문 만으로는 조언의 한계가
    각테이블의 스캔하는 row수 인덱스 어떻게 타는지 등등 여러가지 정보가 많을 수록 더 
    자세한 답변을 들으실듯 하지만 거진 대외비니 실행 계획만이라도 떠서 올려보세요~

    쿼리 보니 답답하네요. 쿨럭~

    by 달빛아우림 [2012.05.29 19:30:28]
    baa07s a,

     and SUBSTR(a.sale_date, 1, 6) = b.book_date(+)
     and SUBSTR(a.sale_date, 1, 6) = c.book_date(+)
     and SUBSTR(A.SALE_DATE, 1, 6) = d.SALE_MON(+)
     and SUBSTR(a.sale_date, 1, 6) = e.book_date(+) and a.sale_date LIKE '2012' || '%' 이렇게 조인 해주셧는데 a테이블을 SUBSTR(a.sale_date, 1, 6) 을 미리 인라인뷰로 그룹핑으로 묶어주시고요~ 조인되는 row수 차이가 무지 크네요.

    by 이재현 [2012.05.29 20:24:06]

    XPLAN ㄱㄱ

    by 마농 [2012.05.30 10:58:46]
    SELECT a.corp_code
         , a.sale_date
         , NVL(b.golfday_cnt , 0) AS golfday_cnt
         , NVL(c.member_count, 0) AS member_count
         , NVL(b.member_team , 0) AS member_team
         , NVL(c.member_front, 0) AS member_front
         , NVL(c.member_lent , 0) + NVL(d.cart, 0)
         - NVL(ROUND(c.member_lent / 1.1 * 0.1), 0)
         - NVL(ROUND(d.cart        / 1.1 * 0.1), 0) AS member_lent
         , NVL(a.member_club_house   , 0) AS member_club_house
         , NVL(a.member_st_club_house, 0) AS member_st_club_house
         , NVL(a.member_west_th      , 0) AS member_west_th
         , NVL(a.member_center_th    , 0) AS member_center_th
         , NVL(c.guest_count         , 0) AS guest_count
         , NVL(b.guest_team          , 0) AS guest_team
         , NVL(c.guest_front         , 0) AS guest_front
         , NVL(c.guest_lent, 0) + NVL(d.n_cart, 0)
         - NVL(ROUND(c.guest_lent / 1.1 * 0.1), 0)
         - NVL(ROUND(d.n_cart     / 1.1 * 0.1), 0) AS guest_lent
         , NVL(a.guest_east_th , 0) AS guest_east_th
         , NVL(a.pro_shop      , 0) AS pro_shop
         , NVL(a.emp_res       , 0) AS emp_res
         , NVL(a.etc_upjang    , 0) AS etc_upjang
         , NVL(a.golf_sum      , 0) AS golf_sum
         , NVL(a.resort_sum    , 0) AS resort_sum
         , NVL(a.last_golfsum  , 0) AS last_golfsum
         , NVL(a.last_resortamt, 0) AS last_resortamt
         , NVL(ROUND(a.golf_sum   / NULLIF(a.last_golfsum  , 0) * 100 - 100), 0) AS golf_compare
         , NVL(ROUND(a.resort_sum / NULLIF(a.last_resortamt, 0) * 100 - 100), 0) AS resort_compare
      FROM (
            SELECT corp_code
                 , SUBSTR(sale_date, 1, 6) sale_date
                 , SUM(DECODE(upjang_code, '1102', net_amt)) AS member_club_house
                 , SUM(DECODE(upjang_code, '1106', net_amt)) AS member_st_club_house
                 , SUM(DECODE(upjang_code, '1103', net_amt)) AS member_west_th
                 , SUM(DECODE(upjang_code, '1104', net_amt)) AS member_center_th
                 , SUM(DECODE(upjang_code, '1105', net_amt)) AS guest_east_th
                 , SUM(DECODE(upjang_code, '1191', net_amt)) AS pro_shop
                 , SUM(DECODE(upjang_code, '1192', net_amt)) AS emp_res
                 , SUM(DECODE(upjang_code, '1199', net_amt)) AS etc_upjang
                 , SUM(DECODE(SUBSTR(upjang_code, 1, 1), '1', net_amt)) AS golf_sum
                 , SUM(net_amt) AS resort_sum
                 , SUM(SUM(DECODE(SUBSTR(upjang_code, 1, 1), '1', net_amt))) OVER(
                   ORDER BY TO_DATE(SUBSTR(sale_date, 1, 6), 'yyyymm)
                   RANGE BETWEEN 12 MONTH PRECEDING AND 12 MONTH PRECEDING
                   ) AS last_golfsum
                 , SUM(SUM(net_amt)) OVER(
                   ORDER BY TO_DATE(SUBSTR(sale_date, 1, 6), 'yyyymm)
                   RANGE BETWEEN 12 MONTH PRECEDING AND 12 MONTH PRECEDING
                   ) AS last_resortamt
              FROM baa07s
             WHERE corp_code = '02'
               AND sale_date BETWEEN ('2012'-1)||'01' AND '2012'||'13'
             GROUP BY corp_code, SUBSTR(sale_date, 1, 6)
            ) a
         , (
            SELECT SUBSTR(gm.book_date, 1, 6) AS book_date
                 , COUNT(DISTINCT gm.book_date) AS golfday_cnt
                 , SUM(DECODE(cs.item1, 1, DECODE(gm.hole_code, '001', 0.5, 1)) AS member_team
                 , SUM(DECODE(cs.item1, 2, DECODE(gm.hole_code, '001', 0.5, 1)) AS guest_team
              FROM gba01m gm
                 , coz10s cs
             WHERE gm.corp_code = '02'
               AND gm.workgrp_code = '100'
               AND gm.book_date LIKE '2012'||'%'
               AND cs.corp_code(+) = gm.corp_code
               and cs.detail(+) = gm.cose
               and cs.head(+) = 'RS511'
               and cs.use_yn(+) = 'Y'
             GROUP BY SUBSTR(gm.book_date, 1, 6)
            ) b
         , (
            SELECT SUBSTR(gd.book_date, 1, 6) AS book_date
                 , SUM(DECODE(cs.item1, 1, DECODE(gm.hole_code, '001', 0.5, 1)) AS member_count
                 , SUM(DECODE(cs.item1, 1, gd.entr_fee)) AS member_front
                 , SUM(DECODE(cs.item1, 1, gd.lent_fee)) AS member_lent
                 , SUM(DECODE(cs.item1, 2, DECODE(gm.hole_code, '001', 0.5, 1)) AS guest_count
                 , SUM(DECODE(cs.item1, 2, gd.entr_fee)) AS guest_front
                 , SUM(DECODE(cs.item1, 2, gd.lent_fee)) AS guest_lent
              FROM gba01d gd
                 , gba01m gm
                 , coz10s cs
             WHERE gd.corp_code = gm.corp_code
               AND gd.workgrp_code = gm.workgrp_code
               AND gd.book_date = gm.book_date
               AND gd.cose = gm.cose
               AND gd.time = gm.time
               AND cs.corp_code = gd.corp_code
               AND cs.detail = gd.cose
               AND cs.head = 'RS511'
               AND cs.use_yn = 'Y'
               AND gd.corp_code = '02'
               AND gd.workgrp_code = '100'
               AND gd.del_yn = 'N'
               AND gd.book_date LIKE '2012'||'%'
             GROUP BY SUBSTR(gd.book_date, 1, 6)
            ) c
         , (
            SELECT SUBSTR(book_date, 1, 6) AS book_date
                 , SUM(DECODE(cose, '007', 0, cart_fee)) AS cart
                 , SUM(DECODE(cose, '007', cart_fee, 0)) AS n_cart
              FROM gbc03s
             WHERE corp_code = '02'
               AND workgrp_code = '100'
               AND book_date LIKE '2012'||'%'
             GROUP BY SUBSTR(book_date, 1, 6)
            ) d
     WHERE a.sale_date LIKE '1012'||'%'
       AND a.sale_date = b.book_date(+)
       AND a.sale_date = c.book_date(+)
       AND a.sale_date = d.book_date(+)
    ;
    

    by 손님 [2012.05.30 15:38:46]
    달빛아우림님
    이재현님
    마농님
    답변 감사드립니다.
    쿼리문 설명을 자세하게 하고 싶었는데, 그렇게 못한게 좀 아쉽네요.
    지금이라도 다시 설명을 드려보자면,
    회원제와 일반제를 구분해서 Select를 해야하는데요.
    그걸 구분하는 부분이
    and 1 = (select item1
         from coz10s
             where gd.corp_code = corp_code
             and head = 'RS511'
             and detail = gd.cose
             and use_yn = 'Y')
    이부분입니다. coz10s테이블에서 select 해온 item1이 1일경우는 회원제이고, 2일경우는 일반제가 됩니다.
    from gba01d gd, gba01m gm
    이 두개의 테이블에서 회원제와 일반제를 구분해서 레코드를 가져와야 하는데,
    member_team,
    member_count,
    member_front,
    member_lent,
    guest_team,
    guest_count,
    guest _front,
    guest_lent
    이렇게 8개의 항목을 두테이블(gba01d , gba01m)에서 회원,일반제를 구분해서 가져와야 하며,

    member_lent, guest_lent 두개의 항목은

    (select SUBSTR(BOOK_DATE, 1, 6) as book_date,
         sum(decode(cose, '007', 0, CART_FEE)) as cart,
         sum(decode(cose, '007', CART_FEE, 0)) as n_cart
       from gbc03s
       where corp_code = '02'
       and WORKGRP_CODE = '100'
       and BOOK_DATE LIKE '2012' || '%'
       group by SUBSTR(BOOK_DATE, 1, 6)) e
    여기서 얻은 cart, n_cart 항목을 더해줘야 합니다. 
    (vat 세금이 포함되어있기때문에, 나중에 vat를 제외해주었습니다.)
    나머지 항목들은 
    baa07s 테이블에서 그저 Select해서 보여주면 되기때문에 문제되지 않습니다.
    종합하자면, 
    member_team, guest_team 두개의 항목은 gba01m 테이블만 있으면 얻어올 수 있으며
    member_count, member_front, guest_count, guest_front 네개의 항목은 
    gba01d, gba01m 테이블을 조인해서 select 하면 되며,
    두 테이블을 조인해서 얻은 member_lent, guest_lent에
    gbc03s에서 얻은 cart, n_cart와 연산하면 구해집니다.

    by 이수달 [2012.05.30 15:50:36]
    어익후; 로그인을 안했군요;

    by 마농 [2012.05.30 15:54:52]

    전반적이 설명이 없어 쿼리만 보고 튜닝했습니다만...
    추가로 언급하신 부분에 대해서는 나름 다 적용한듯 합니다.
    쿼리 재검토 바랍니다.


    by 이수달 [2012.05.30 16:32:13]
    오 마농님의 쿼리를 오탈자만 수정해서 돌려보니 결과가 잘 나오는군요.
    오라클의 신세계를 본 느낌입니다. ㅋㅋ

    윈오우 함수? 라는건 처음본거고, 이 프로젝트내에서도 본적이 없어서
    잘 모르겠더군요. (저는 쿼리 자체를 이 프로젝트에서 처음 접했습니다.)
    한번 찾아봐야겠습니다.

    아무튼 다시한번 감사드립니다.
    댓글등록
    SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
    로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입