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)
이건 뭐 몇 십분을 기다려도 답이 안나오더군요....
어떻게 해야 가장 성능이 좋은 방법일까요?
*그룹핑하기 전 조회결과 값은 약 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);
아직 초보자 수준이라... 여러 방법을 찾아서 이리저리 해보고 있는데.... 저 쿼리가 맞는건지도 모르겠네요...
읽어주시고 조언해주셔서 감사합니다.
시퀀스로 unique한 값을 만드시는군요.
사용하신 방법대로 수행하시면 update가 row별로 수행되기 때문에 row별로 다른 값이 지정됩니다.
그룹별로 unique한 값 지정이 안 된다는 말이지요.
제 생각에는 그룹이 300개이면 loop 돌면서 300번 update 하는 게 나아보이구요.
성능에 대해서는 인덱스를 사용하는 게 빠를 수도 있고 느릴 수도 있지만..
일단 col1~col6이 각각 단일 인덱스인가요? 아니면 복합인덱스인가요?
복합인덱스일 경우 그나마 인덱스 활용하는 게 나을 수도 있지만
단일인덱스로 여러개 있다면 다른 방법을 찾아봐야할 것 같아요.
답변 감사합니다.^^
ON 절의 조건으로 그룹핑된 ROW들을 업데이트 하도록 하고 싶었어요...예를 들면 총 십만건 중에 ON절의 조건으로 GROUP BY한 결과가 만 건이라고 치고... 그 그룹 만 건중 1개가 100개의 row에 해당 (100개의 row가 ON 절의 조건으로 그룹핑) 한다면 이 100개의 row가 하나의 시퀀스 값으로 일괄 업데이트 하도록 하는 부분인데... 즉, 그룹 ID라 되겠네요.. 근데 쿼리가 잘못되었나보네요...^^; 결국 업데이트는 십만건 ROW에 다 해야하는 상황이죠.... ROW별로 그룹 아이디를 부여하고 싶었는데 힘드네요 이게...
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만 건 정도면 그렇게 오래 걸리지 않을 것 같네요.