MARGE INTO target_name USING (table|view|subquery) ON (join condition) WHEN MATCHED THEN UPDATE SET col1 = val1[,col2=val2] WHEN NOT MATCHED THEN INSER(....) VALUES(....) - INTO : DATA가 UPDATE 되거나 INSERT될 TABLE 이름을 지정합니다. - USING : 대상 TABLE의 DATA와 비교한 후 UPDATE 또는 INSERT할 대상이 되는 DATA의 SOURCE 테이블 또는 뷰를 지정 - ON : UPDATE나 INSERT를 하게 될 조건으로, 해당 condition을 만족하는 DATA가 있으면 WHEN MATCHED절을 시행하게 되고 없으면 WHEN NOT MATCHED 을 실행하게 됩니다. - WHEN MATCHED : ON 조건절이 TRUE인 ROW에 수행할 내용 - WHEN NOT MATCHED : ON 조건절에 맞는 ROW가 없을 때 수행할 내용.
![]() |
|
![]() |
|
Case1: Statement를 재활용하지 않는 경우 startTime = System.currentTimeMillis(); for(int idx=1;idx<=10000; idx++){ pstmt = conn.prepareStatement("SELECT /* NO REUSER */ 1 FROM java_test WHERE ROWNUM = ?"); pstmt.setInt(1,1); ResultSet rs = pstmt.executeQuery(); pstmt.close(); //커서를 즉시 닫는다. } endTime = System.currentTimeMillis(); System.out.println("Case1: "+ (endTime - startTime )/10 + " (cs) elapsed"); Case2: Statement를 재활용하는 경우 startTime = System.currentTimeMillis(); for(int idx=1;idx<=10000; idx++){ pstmt = conn.prepareStatement("SELECT /* NO REUSER */ 1 FROM java_test WHERE ROWNUM = ?"); pstmt.setInt(1,1); ResultSet rs = pstmt.executeQuery(); //커서를 닫지 않고 재활용한다. } pstmt.close(); endTime = System.currentTimeMillis(); System.out.println("Case2: "+ (endTime - startTime )/10 + " (cs) elapsed"); //------ output Case1: 7136 (cs) elapsed Case2: 1015 (cs) elapsed
Case1: Batched Execution을 사용하지 않는 경우 startTime = System.currentTimeMillis(); pstmt = conn.prepareStatement("UPDATE/* NO BATCH*/ java_test SET id=id WHERE ROWNUM = ?"); for(int idx=1;idx<=10000; idx++){ pstmt.setInt(1,1); pstmt.executeUpdate(); //매번 수행한다. } pstmt.close(); endTime = System.currentTimeMillis(); System.out.println("Case1: "+ (endTime - startTime )/10 + " (cs) elapsed"); Case2: Batched Execution을 사용하는 경우 startTime = System.currentTimeMillis(); pstmt = conn.prepareStatement("UPDATE/* NO BATCH*/ java_test SET id=id WHERE ROWNUM = ?"); for(int idx=1;idx<=10000; idx++){ pstmt.setInt(1,1); pstmt.addBatch(); //매번 수행하는 대신 ddBatch를 이용해 요청을 모은다. } pstmt.executeBatch(); //addBatch를 통해 모아둔 요청을 한꺼번에 수행한다. endTime = System.currentTimeMillis(); System.out.println("Case2: "+ (endTime - startTime )/10 + " (cs) elapsed"); //------ output Case1: 1839 (cs) elapsed Case2: 270 (cs) elapsed
Case1: Fatch size를 10으로 설정한 경우 startTime = System.currentTimeMillis(); pstmt = conn.prepareStatement("SELECT /* SMALL FETCH SIZE */ 1 FROM java_test"); pstmt.setFatchSize(10); //작은 패치 크기 for(int idx=1;idx<=10000; idx++){ ResultSet rs = pstmt.executeQuery(); while(rs.next()) {} //모든 로우를 패치 } pstmt.close(); endTime = System.currentTimeMillis(); System.out.println("Case1: "+ (endTime - startTime )/10 + " (cs) elapsed"); Case2: Fatch size를 100으로 설정한 경우 startTime = System.currentTimeMillis(); pstmt = conn.prepareStatement("SELECT /* SMALL FETCH SIZE */ 1 FROM java_test"); pstmt.setFatchSize(10); //큰 패치 크기 for(int idx=1;idx<=10000; idx++){ ResultSet rs = pstmt.executeQuery(); while(rs.next()) {} //모든 로우를 패치 } pstmt.close(); endTime = System.currentTimeMillis(); System.out.println("Case2: "+ (endTime - startTime )/10 + " (cs) elapsed"); //------ output Case1: 1509 (cs) elapsed Case2: 396 (cs) elapsed
SQL Trace결과를 비교해보면, 성능 차이를 결정짓는 요소는 페치(Fetch) 횟수라는 것을 알 수 있다. 페치 크기가 10인 경우에는 페치 횟수가 15,000번에 달하는 반면, 100인 경우는 2,000에 불과하다.
더 재미있는 사실은 Logical Reads(query)페치 크기가 줄어든다는 사실이다!!! (각자 trace떠보셈)
그렇지만 이것 또한 부적절하게 사용하면 자원의 경합을 유발할 수 있기 때문에 대량의 추출하는 특정 모듈에서만 큰 페치 크기를 적용하라.
구분 | FATCH | SELECT ... INTO |
---|---|---|
용도 | N건의 ARRAY FETCH | 한번의 ARRAY FETCH |
MAX값을 모를때 MAX가 지나치게 넓어서 한번의 FETCH로는 무리한 경우 |
MAX를 알때 | |
주의점 | Loop Query SQL 내에 cursor문을 다시 declare 해서는 절대 안됨 | Loop 내에 반복되는 n건 처리 Declare SQL에서 Join 하여 해결 |
병렬 처리는 보약이 될 수 있다. 큰 문제를 여러 개의 보다 작은 문제로 나누면(분할 접근법) 처리 시간을 획기적으로 줄일 수 있다. 그러나 병렬 처리는 독이 될 수도 있다. 병렬 처리를 많은 부류의 문제에 적용하면 이들의 속도를 저하시킬 뿐만 아니라 엄청난 리소스를 소비한다.
병렬 쿼리의 시작비용은 매우 높기 때문에 대상 쿼리가 실제로는 느리게 시작된다.
create table T nologging parallel as select * from external_table |
---|
여기서 병렬 처리의 정도는 이용 가능한 리소스에 근거하여 오라클 자체에 의해 선택 될 수 있다.
대용량 데이터에 대한 DDL 수행시 Parallel 옵션을 적절히 사용하면 DDL 자체의 성능을 극대화할 수 있다. 더불어 Nologging 옵션을 함께 사용해도 좋다. DDL의 수행속도가 향상되면, 그에 비례해서 TX락 경합에 의한 대기시간도 줄어들게 된다.
병렬 쿼리는 성능문제를 해결하면서 시도하는 마지막 수단이지 결코 첫 번째 경로는 아니다.
병렬 쿼리는 동시 사용자의 수가 낮은 데이터 웨어하우스에 유용한 기능이다. CPU가 64개이고 동시사용자 수가 500인 데이터 웨어하우스에는 병렬 쿼리가 적합하지 않을 것이다. 그러나 CPU가 64개이고 동시 사용자 수가 5인 데이터 웨어하우스에는 병렬 쿼리가 훌륭한 솔루션이 될 수 있다.
병렬 DML(PDML)은 실제로 CREATE TABLE, CREATE INDEX, 또는 적재와 유사한 관리 기능으로서 어쩌다 레거시 데이터를 고치기 위하여 한 번에 대용량 UPDATE 또는 DELETE를 수행하기 위하여 사용된다.
위의 제약사항을 하나라도 위반하면 PDML작업을 시도하면 오류 메시지를 받지는 않지만 문이 직렬로 수행된다. V$PX_PROCESS와 같은 동적 성능 뷰를 이용하면 문의 병렬 처리를 모니터링할 수 있다.