database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
PostgreSQL
Firebird
ㆍOracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
Oracle Q&A 40559 게시물 읽기
No. 40559
프로시져 속도 향상 문의 드립니다.
작성자
야간비행(야간비행)
작성일
2014-08-20 12:45
조회수
8,744
아래와 같은 프로시져가 있습니다.
수행 속도가 5분정도 되어서 어디가 문제인지 여쭤보려합니다.
 
cusor_A의 데이터 갯수는 약 만개 정도이며
cusor_A에서 구한 데이터를 가지고 TMP_SQL를  array1 사이즈 4개를 수행하면 총 4만번정도 수행할거라 여겨집니다.
=> cursor_A, tmp_sql 쿼리 수행시간은 각각 5초,1초 내외입니다.
    ( tab1  테이블에 데이터가 좀 많긴 합니다. 5억건 정도)
 
전체 수행시간이 너무 시간이 오래걸립니다.
속도 향상 방법이 없을까요??
 
 
CREATE OR REPLACE PROCEDURE procedureA
IS
 
BEGIN
  
    DECLARE
 
    var1             VARCHAR2(100);
    var2             VARCHAR2(100);
    var3             NUMBER(10);
    
    TMP_SQL          VARCHAR2(4000);
 
    TYPE COMPAREARRAY  IS  VARRAY(10) OF VARCHAR2(50);
    array1   COMPAREARRAY;
    array2   COMPAREARRAY;
    
    CURSOR cusor_A IS 
    SELECT DISTINCT A.cols1, A.cols2, D.cols3,  '201428' cols4
      FROM tab1 A, tab2 D, tab3 G
     WHERE 1 = 1
       AND D.cols1 = A.cols1
       AND D.cols5 = A.cols5       
       AND G.cols1 = A.cols1       
       AND G.cols2 = A.cols2
       AND G.cols3 = D.cols3
       AND A.cols1 = 'TEST'
       AND A.cols6 = 'D'
       AND A.cols7 BETWEEN '20140707' AND '20140713'
       AND A.cols9 != 0
       ;
    
     BEGIN
         
         array1 := COMPAREARRAY('L','U','N','T'); 
         array2 := COMPAREARRAY('E','B','M','A');          
                            
        FOR BASE IN cusor_A
        LOOP 
 
            FOR I IN array1.FIRST .. array1.LAST            
            LOOP
                    
                    TMP_SQL := '  SELECT COUNT(*) AS CNT '|| 
                       '     FROM ( '||
                       '              SELECT A.cols10,(CASE '||
                       '                            WHEN A.cols11 = ''PID_'' || A.cols1 '||
                       '                            THEN ''TEST'' '|| 
                       '                            WHEN A.cols11 = ''PID_'' || A.cols1 '||
                       '                            THEN ''TEST'' '|| 
                       '                            ELSE ''SAMPLE'' '||
                       '                      END) AS GOOD '||
                       '               FROM tab1 A, '||
                       '                    tab2 D, '||
                       '                    tab3 G '||
                       '              WHERE     1 = 1 '||
                       '                AND D.cols1 = A.cols1 '||
                       '                AND D.cols5 = A.cols5 '||       
                       '                AND G.cols1 = A.cols1 '||
                       '                AND G.cols2 = A.cols2 '||
                       '                AND G.cols3 = D.cols3 '||
                       '                AND A.cols1 = '''||BASE.cols1||''' '||
                       '                AND A.cols2 = '''||BASE.cols2||''' '||
                       '                AND D.cols3 = '''||BASE.cols3||''' '||                       
                       '                AND A.cols10  =  '''||array2(I)||''' '||
                       '                AND A.cols6      = ''D'' '||
                       '                AND A.cols7 BETWEEN ''201428'' AND  ''201428'' '||
                       '                AND A.cols9 != 0 '||
                       '           ) A '||
                       '      WHERE cols8  = '''||array1(I)||''' '; 
                                                                              
                    EXECUTE IMMEDIATE TMP_SQL INTO var3;                                                                  
                    
                    var1 := array1(I);
                    var2 := array2(I);
                    
                    IF var3 >=1 THEN                                                                                                                                                 
                        GOTO LABEL_INNER;
                    END IF;
 
            END LOOP;
                
            <<LABEL_INNER>>
            NULL;                                      
                                      
        END LOOP;
        
    END;
    
    COMMIT;
                    
END;
/
 
이 글에 대한 댓글이 총 5건 있습니다.

1. 동적SQL 사용할 때도 바인드 변수 사용 가능합니다.
  - 리터럴 값 사용으로 인한 하드파싱 횟수가 감소(4만회==>1회)됩니다.
2. 굳이 동적SQL 로 하지 않아도 될 듯 한데요.
  - 정적SQL 로 해도 상관 없을듯 합니다. 오히려 더 깔끔할 듯.
3. 로직 변경도 고려해 볼만 합니다.
  - 서브로직 4번 수행되는 것을 한번 수행으로 바꿀수 있을 듯 하구요
  - 서브로직을 없애고 메인 한방 SQL 로의 변경도 가능하리라 생각됩니다.

마농(manon94)님이 2014-08-20 17:06에 작성한 댓글입니다.

 감사합니다. 마농님.

2,3번을 수행해봤는데 반절정도 줄어드는 효과가 있는거 같습니다.

1번에 대해서 바인드 변수를 사용하시라 했는데 어떻게 사용하는지 제가 이해가 안가는데요.

게시판 조회해서 한번 해보겠습니다.

정말 감사합니다.

야간비행(야간비행)님이 2014-08-20 18:40에 작성한 댓글입니다.

동적쿼리에서 바인드변수 사용 방법
○ SQL 구문
 - 변경전 : ' AND A.cols1 = '''||BASE.cols1||''' '
 - 변경후 : ' AND A.cols1 = :v_cols1 '
○ EXEC 구문
 - 변경전 : EXECUTE IMMEDIATE TMP_SQL INTO var3;
 - 변경후 : EXECUTE IMMEDIATE TMP_SQL INTO var3 USING BASE.cols1;

마농(manon94)님이 2014-08-20 18:57에 작성한 댓글입니다.

 음...바인드 변수 처리해서 했더니 오히려 두배나 속도가 더 느려졌네요..ㅠㅠ

아...뭘 잘못 했지.ㅡㅡ

야간비행(야간비행)님이 2014-08-20 19:25에 작성한 댓글입니다.

 루프 문 안에서 BIND변수를 쓰는게 일단 정석입니다.

 

BIND적용으로 파싱 오버헤드는 처리하신 듯 한데...

 

BIND 변수를 적용하면서 실행 계획이 변동된 듯 싶네요.  BIND 변수를 사용할 경우 단점은 칼럼 히스토그램 정보를 활용하지 못하므로 값의 분포도가 한 쪽으로 치우쳤을 때 정확한 실행 계획이 나오지 못하는 단점이 있습니다.  

수정 Before/After Plan 비교해서 힌트 등으로 고정하시기 바랍니다.

김주현님이 2014-08-21 08:54에 작성한 댓글입니다. Edit
[Top]
No.
제목
작성자
작성일
조회
40563쿼리 질문 드립니다. [1]
야간비행
2014-08-26
7628
40561대용량 xml구조 데이타 insert select [1]
json
2014-08-22
9333
40560기간내 해당하는 데이타 추출하기 [1]
너구리
2014-08-22
8367
40559프로시져 속도 향상 문의 드립니다. [5]
야간비행
2014-08-20
8744
40558합격자 선발 SQL 작성 방법? [4]
김기석
2014-08-18
8233
40555쿼리 문의(세로를 가로로...) [1]
박지연
2014-08-11
8595
40554테이블스페이스 크기 문의드려요... [1]
이영우
2014-08-08
7250
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.018초, 이곳 서비스는
	PostgreSQL v16.2로 자료를 관리합니다