GROUP BY 된 결과 값 업데이트 하는 최적의 방법은(대용량데이터) ??? 0 9 4,638

by 게릴라 [SQL Query] 대용량데이터업데이트 groupby [2016.12.26 14:26:11]


안녕하세요.

오라클 쿼리 튜닝 작업 중에 질문이 있어 문의드립니다.

A라는 테이블에 수백만건의 데이터가 있습니다.

특정조건으로 SELECT하면 수만건에서 수십만건이 나오고,

이 결과를 특정컬럼 a,b,c로 GROUP BY합니다.

a,b,c 컬럼은 그룹핑 조건이며, 그룹핑된 row별로 UNIQUE한 값을

부여하려고 합니다. 

처음엔 GROUP BY 하지않고 전체 ROW를 SELECT하여,

루프를 돌면서 a,b,c 컬럼 값이 같은 ROW에 일일이 UNIQUE한 값을

부여했습니다. 너무나 느리더군요.

그 다음...해본 방법이..

SELECT (/*+ BYPASS_UJVC */) UPDATE구문도 GROUP BY 때문에 안되더라구요.

그 다음엔... 서브쿼리로 해보았습니다.

UPDATE A

SET GROUP_UNIQUE_VAL = 그룹별 고유아이디

WHERE EXISTS (SELECT ... GROUP BY a,b,c)

이건 뭐 몇 십분을 기다려도 답이 안나오더군요....

어떻게 해야 가장 성능이 좋은 방법일까요?

by jkson [2016.12.26 14:31:38]

제 짧은 소견으로는 MERGE문이 좋지 않나 생각이 듭니다만.. 운영중인 데이터라면 한방에 수십만건 다 업데이트 하시기 보다는 적당히 끊어서 하시는 게 좋을 듯 싶네요.


by 게릴라 [2016.12.26 18:14:29]

답변 감사합니다. Merge문으로 수행해봤더니 역시나 너무 느려서 포기했습니다.

Merge문 USING 절에 Group By로 select하고 ON 절에서 SELECT한 컬럼값으로 조건 걸고..

실행했더니 너무나 오래 걸려서 Merge문 작성방법은 포기했습니다.ㅜ


by 우리집아찌 [2016.12.26 15:11:27]

프로시져로 만드셔서 커서 만드신후 루프돌려서 update 하시고 커밋 단위를 짧게 가져가세요

운영중이시면 새벽에 돌려야 하실듯한다

도중에 데이터 변경이 일어날 가능성이 있는 레코드인지 확인하셔야 합니다


by 게릴라 [2016.12.26 18:53:34]

네..답변 감사합니다.

한방에 최대한 빠르게 처리할라고 어떻게든 알아보았는데..

결국 커서에서 GROUP BY SELECT하고 그 그룹단위로 루프돌면서

업데이트하는 로직 작성 중입니다.

이건 얼마나 오래 걸리지...^^; 

정말 생각보다 너무 오래 걸려서 멘붕이네요...

 

 


by 마농 [2016.12.26 18:54:50]

테이블 정보, 인덱스 정보 , 사용하신 쿼리 등을 보여주세요.


by 게릴라 [2016.12.27 14:57:04]

*그룹핑하기 전 조회결과 값은 약 10만건..
*COL1~COL6로 그룹핑하면 결과 값은 약 300건..

*10만건 각 ROW에 대하여,  GROUP BY로 그룹핑된 ROW들별로 고유아이디 업데이트 수행. 
(1행부터 20행이 하나의 그룹으로 묶였다면 1~20행은 같은 고유아이디로 업데이트)

*TABLE의 PK는 5개이지만 쿼리에서 사용하는 Key컬럼은 이 중 COL1,COL2,COL3만 사용
*인덱스는 COL1~COL6로 인덱스 잡혀있음.

 

MERGE /*+ use_nl(SOURCE TARGET) */  INTO TABLE TARGET
USING (SELECT A.COL1
              ,A.COL2
              ,A.COL3
              ,A.COL4
              ,A.COL5
              ,A.COL6
          FROM TABLE A        
         WHERE A.COL1 = 값
        AND A.COL2 = 값
        AND A.COL3 = 값
        AND A.COL4 = 값
        AND A.COL7 = 값
        AND A.COL8 = 값
        AND A.COL9 = 값
        AND A.COL10 <> 값
        AND A.COL11 <> 값
         GROUP BY A.COL1
              ,A.COL2
              ,A.COL3
              ,A.COL4
              ,A.COL5
              ,A.COL6) SOURCE 
ON (TARGET.COL1 = SOURCE.COL1
    AND TARGET.COL2 = SOURCE.COL2
    AND TARGET.COL3 = SOURCE.COL3
    AND TARGET.COL4 = SOURCE.COL4
    AND TARGET.COL5 = SOURCE.COL5
    AND TARGET.COL6 = SOURCE.COL6) 
WHEN MATCHED THEN UPDATE SET TARGET.COL_UID = TO_CHAR(SYSDATE,'YYYYMMDD') || LPAD(SEQ_UID.NEXTVAL,9,0);


아직 초보자 수준이라... 여러 방법을 찾아서 이리저리 해보고 있는데.... 저 쿼리가 맞는건지도 모르겠네요...
읽어주시고 조언해주셔서 감사합니다.


by jkson [2016.12.28 08:05:52]

시퀀스로 unique한 값을 만드시는군요.

사용하신 방법대로 수행하시면 update가 row별로 수행되기 때문에 row별로 다른 값이 지정됩니다.

그룹별로 unique한 값 지정이 안 된다는 말이지요.

제 생각에는 그룹이 300개이면 loop 돌면서 300번 update 하는 게 나아보이구요.

성능에 대해서는 인덱스를 사용하는 게 빠를 수도 있고 느릴 수도 있지만..

일단 col1~col6이 각각 단일 인덱스인가요? 아니면 복합인덱스인가요?

복합인덱스일 경우 그나마 인덱스 활용하는 게 나을 수도 있지만

단일인덱스로 여러개 있다면 다른 방법을 찾아봐야할 것 같아요.

 


by 게릴라 [2016.12.28 10:29:00]

답변 감사합니다.^^

ON 절의 조건으로 그룹핑된 ROW들을 업데이트 하도록 하고 싶었어요...예를 들면 총 십만건 중에 ON절의 조건으로 GROUP BY한 결과가 만 건이라고 치고... 그 그룹 만 건중 1개가 100개의 row에 해당 (100개의 row가 ON 절의 조건으로 그룹핑)  한다면 이 100개의 row가 하나의 시퀀스 값으로 일괄 업데이트 하도록 하는 부분인데... 즉,  그룹 ID라 되겠네요.. 근데 쿼리가 잘못되었나보네요...^^; 결국 업데이트는 십만건 ROW에 다 해야하는 상황이죠.... ROW별로 그룹 아이디를 부여하고 싶었는데 힘드네요 이게...

 


by jkson [2016.12.28 11:19:06]

1회에 한하여 전체 업데이트하시는 건가요? 그렇다면..

인덱스 활용이고 뭐고 복잡하다고 생각되시면


해당 테이블을 col1~col6까지 그룹지어서 그룹결과를 아래와 같은 컬럼으로 구성된 임시 테이블에 저장하세요.
col1 , col2, col3, col4, col5, col6, col_uid

insert into 임시테이블
select col1,col2,col3,col4,col5,col6, null from 타겟테이블
group by col1,col2,col3,col4,col5,col6

그렇게 저장하시고 임시테이블의 col_uid에 값을 할당해주세요.
그리고 타겟 테이블에 merge문 날려보세요.

merge into 타겟테이블 a
using 임시테이블 b
on (a.col1 = b.col1
and a.col2 = b.col2
and a.col3 = b.col3
and a.col4 = b.col4
and a.col5 = b.col5
and a.col6 = b.col6)
when matched then
update set a.col_uid= b.col_uid


100만 건 정도면 그렇게 오래 걸리지 않을 것 같네요.

 

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