11g 에서 bypass_ujvc 대체 쿼리 문의드립니다. 0 20 10,348

by 힐포인트 [SQL Query] [2012.09.20 13:54:39]


-- 법정동 - 읍면동리 명으로 등록된 우편번호 법정코드 등록
UPDATE /*+ bypass_ujvc */
      (SELECT A.BUBJUNG_CD AS A_BUBJUNG_CD, B.BUBJUNG_CD AS B_BUBJUNG_CD
         FROM (SELECT ZIP_CODE,
                      ZIPCODE,
                      POST_SIDO,
                      POST_SIGUN,
                      POST_DONG,
                      POST_RI,
                      POST_BUNJI,
                      POST_BUILD,
                      REG_DT,
                      FULL_NM,
                      BUBJUNG_CD,
                      POST_SIDO || REPLACE(POST_SIGUN, ' ', '') || POST_DONG || POST_RI AS BUB_NM
                 FROM TMP_CM_POST_T) A
              LEFT JOIN
              (SELECT BUBJUNG_CD,
                      HANGJUNG_SD_NM ||
                      CASE WHEN SUBSTR(BUBJUNG_CD, 6, 5) = '00000'
                           THEN REPLACE(HANGJUNG_SK_NM,' ', '')
                           ELSE REPLACE(HANGJUNG_SK_NM,' ', '') ||
                      CASE WHEN SUBSTR(BUBJUNG_CD, 9, 2) = '00'
                           THEN BUBJUNG_NM
                           ELSE HANGJUNG_UP_NM || BUBJUNG_NM END END AS BUB_NM
                     ,SUBSTR(BUBJUNG_CD, 6, 4)
                     ,SUBSTR(BUBJUNG_CD, 8, 2)
                 FROM TMP_CM_POST_BUBHANG) B
           ON A.BUB_NM = B.BUB_NM
        WHERE B.BUBJUNG_CD IS NOT NULL)
  SET A_BUBJUNG_CD = B_BUBJUNG_CD;



기존 까지는 서버가 10g 여서 위의 쿼리가 잘돌아 갔는데 11g로 업그레이드 하는 바람에 위의 쿼리가 실행이 안됩니다.
힌트를 빼고 하면 ORA-01779: 키-보존된것이 아닌 테이블로 대응한 열을 수정할 수 없습니다 라고 나오고 
merge into 를 사용해서 고치고 있다가 머지를 쓰지말라고 하여서 어떤식으로 해야 할지...감이 안오네요
도움좀 부탁드리겠습니다...
by 무지개 [2012.09.20 14:01:43]
11g 부터 해당 힌트를 사용하실 수 없을 겁니다. merge 문으로 변환하시는게 나을듯 합니다.
혹시 다른 방법 알고 계신분 있으시면 답변을 부탁드립니다.

by 힐포인트 [2012.09.20 14:40:11]
ㄴ 머지로 해서 쿼리문을 짜봤는데 1:1 매핑이 아닌지 A 테이블 의 BUBJUNG_CD 전체가 아닌 부분만 업데이트 되더군요..
MERGE /*+ USE_HASH */
INTO
(SELECT BUBJUNG_CD
       ,TRIM(SUBSTR(POST_SIDO,1,2)||POST_SIGUN||POST_DONG||POST_RI) AS BUB_NM
 FROM TMP_CM_POST_T
) A
USING
(SELECT DISTINCT(BUBJUNG_CD)
      ,HANGJUNG_SD_NM ||
       CASE WHEN SUBSTR(BUBJUNG_CD, 6, 5) = '00000'
            THEN REPLACE(HANGJUNG_SK_NM,' ', '')
            ELSE REPLACE(HANGJUNG_SK_NM,' ', '') ||
       CASE WHEN SUBSTR(BUBJUNG_CD, 9, 2) = '00'
            THEN BUBJUNG_NM
            ELSE HANGJUNG_UP_NM || BUBJUNG_NM END END AS BUB_NM
FROM TMP_CM_POST_BUBHANG
WHERE BUBJUNG_CD IS NOT NULL) B
ON (A.BUB_NM = B.BUB_NM)
WHEN MATCHED THEN
UPDATE
SET A.BUBJUNG_CD = B.BUBJUNG_CD; 

이렇게 짰는데 DISTINCT를 안하면 ORA-30926 에러가 나서 B의 BUBJUNG_CD에 DISTINCT를 걸어주었는데
이것때문인지 전체 업데이트가 안되고 일부분의 로우만 업데이트가 되네요...

by 이재현 [2012.09.20 16:44:35]

그럼 B의 조건이 A의 전체에 만족하지 못합니다.

우선 업데이트를 하지마시고 A테이블을 아웃터 조인으로 확인해보셔요.


by 마농 [2012.09.20 18:05:22]
MERGE INTO tmp_cm_post_t a
USING
(
SELECT a.rid
     , b.bubjung_cd
  FROM (SELECT ROWID rid
             , bubjung_cd
             , post_sido || REPLACE(post_sigun, ' ', '')
               || post_dong || post_ri AS bub_nm
          FROM tmp_cm_post_t
        ) a
     , (SELECT bubjung_cd,
               hangjung_sd_nm ||
               CASE WHEN SUBSTR(bubjung_cd, 6, 5) = '00000'
                    THEN REPLACE(hangjung_sk_nm,' ', '')
                    ELSE REPLACE(hangjung_sk_nm,' ', '') ||
               CASE WHEN SUBSTR(bubjung_cd, 9, 2) = '00'
                    THEN bubjung_nm
                    ELSE HANGJUNG_up_nm || bubjung_nm END END AS bub_nm
          FROM tmp_cm_post_bubhang
        ) b
 WHERE a.bub_nm = b.bub_nm
   AND b.bubjung_cd IS NOT NULL
) b
ON (a.ROWID = b.rid)
WHEN MATCHED THEN
UPDATE SET bubjung_cd = b.bubjung_cd
;

by 힐포인트 [2012.09.21 10:07:55]

ㄴ 재현님 답변 감사드려요 ~
마농님 답변 감사드립니다 ~!
    근데 merge 자체가 속도가 느린가요???
    쿼리를 돌려보다 15분이상 계속 돌아서 취소를 했어요 ㅎㅎ;;
    update 문하고 속도차가 피부에 느껴지는거 같아요..

by 최성호 [2012.09.21 10:34:35]

UPDATE 조건에 EXISTS 를 추가하는게 더 좋지 않나요?

by 최성호 [2012.09.21 10:39:33]
 UPDATE 대상 A AS T(TARGET 약자)
  SET(
업데이트대상 칼럼들
) = (
SELECT
업데이트 데이타 칼럼들
FROM 대상 A  AS S( SORECE 의 약자)
, JOIN 될 칼럼들
WHERE
대상 A 칼럼과 JOIN 될 테이블들의 JOIN 조건

S.PK칼럼 = T.PK 칼럼

)

WHERE EXISTS (
SELECT
'X' -- 의미없는 문자데이타, 단지 해당로우가 존재하는지 확인하는용 
   FROM 대상 A AS S( SORECE 의 약자)
   , JOIN 될 칼럼들
WHERE
대상 A 칼럼과 JOIN 될 테이블들의 JOIN 조건
S.PK칼럼 = T.PK 칼럼
)

이렇게 쓰는게 오라클 자원도 덜 소비하고 더 빠른것으로 알고 있습니다.

by 최성호 [2012.09.21 10:40:21]
 위에 댓글에 조인될칼럼들이 아니라 JOIN 할 테이블들로 정정합니다.

by 힐포인트 [2012.09.21 10:43:38]

ㄴ 성호님 폭풍 댓글 감사합니다 .
    안그래도 업데이트 문 으로 바꿀려고 하는 중이였는데 참고 하겠습니다 ^^

by 마농 [2012.09.21 10:55:54]
일단 조인컬럼이 인덱스가 있는것이 아니고 가공된 컬럼이라서 쿼리 자체가 느릴것 같구요.
우편번호 테이블이라면 데이터량도 상당할것 같네요.
이상태에서는 Update 에서 Exists 로 체크하는것이 속도가 더 좋을리가 없을 듯 합니다.
업데이트 대상테이블을 루핑 돌면서 서브쿼리를 반복 수행해야 하거등요.
보통 Update, Exists 에서 속도가 안나올때 Merge 로 바꿔 속도 개선하지요.
Using 절에서 사용한 서브쿼리 속도는 얼마나 나오나요?

by 최성호 [2012.09.21 11:08:45]

마농님 감사합니다. 참고 하겠습니다.

by 최성호 [2012.09.21 11:09:18]
 제가 문장을 잘못봤네요;

by 힐포인트 [2012.09.21 11:10:06]

ㄴ Using 절의 서브 쿼리 속도는 0.172초 걸리는데 merge를 돌렸을 경우 15분이상 계속 딜레이 되서 쿼리수행을 취소 했습니다 마농님 ㅠㅠ
tmp_cm_post_t 는 약 5만2천건 , tmp_cm_post_bubhang 은 약 2만2천건정도 되구요..using절 건수는 1만7천건 정도 되네요!!

by 마농 [2012.09.21 11:21:43]

USING 절 안에서 ORDER BY rid 를 추가해 보세요.


by 최성호 [2012.09.21 11:23:58]

마농님 질문있습니다. 저도 이런것을 써야할 곳이 있어서. 뭔가 이유를 알고 쓰고 싶습니다.

USING 절 안에서 ORDER BY rid 의 의미가 무엇인가요?

by 마농 [2012.09.21 11:34:09]

ROWID 는 레코드의 주소입니다.
ROWID 를 이용해 레코드를 바로 찾아 업데이트 하려고 한거구요.
정렬이 안된 상태에서 레코드를 뒤죽박죽 찾다보면 블럭IO 가 증가하게 됩니다.
그래서 정렬을 하면 혹시나 효과가 있지 않을까 생각했습니다.


by 힐포인트 [2012.09.21 11:41:23]
마농님!
말씀하신데로 USING 절에 ORDER BY 를 했는데요 ~
ORA-30926: 원본 테이블의 고정 행 집합을 가져올 수 없습니다
라는 오류가 납니다...

by 마농 [2012.09.21 12:45:06]

그렇다면
서브쿼리 결과가 1:1 조인이 아닌 1:다 조인이 되었다는 것입니다.
하나의 ROWID 에 업데이트할 값이 두개가 붙었다는 것이죠.
서브쿼리 결과를 점검하세요.


by 최성호 [2012.09.21 13:00:01]

감사합니다. ^^

by 힐포인트 [2012.09.21 13:18:26]
ㄴ 리플 달아주신 무지개님, 이재현님 , 최성호님  그리고 마농님 정말 감사드려요 ^^ 서브쿼리를 점검해서 새로 쿼리를 짜봐야겠네요 ^^ 다들 좋은 주말 보내세요  
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입