오라클 or절 하나만 더 질문드릴게요 0 7 603

by 김첨지의럭키데이 [Oracle 기초] [2019.05.14 10:54:56]


SELECT * FROM PRODUCT
WHERE  ((PARAM_BRANDCODE IS NOT NULL  and (BRANDCODE IN ('B001','B002'))) OR (PARAM_BRANDCODE IS  NULL  and(1=1)));

 

역시나 저번 질문이랑 비슷한건데 제가 응용력이 없는지 이걸  or절 안쓰고 어떻게 튜닝해야할지 잘모르겠네요

 

PARAM_BRANDCODE  브랜드 코드 파라미터입니다  'B001,B002' 이런식으로 여러 개 동시에에 넘길수도 있고 아무것도 안넘길수도 있습니다 

아무것도 안넘기면 전체검색(1=1)이고 넘어가면 in절로 검색해야되는데 이게 or구문안쓰고 어떻게 가능할까요? 실행계획봐도 OR절은 풀스캔되서 코스트가 대박이라 영 별로네요 매번 도움만 받는거같아서 죄송하네요 ㅜ

 

UNION ALL 라는 대체법이 있는건 알지만 안그래도 긴 쿼리가 너무 길어져서 일단 보류중입니다

by 마농 [2019.05.14 11:26:59]

파라미터가 구분자를 포함한 여러값이 넘어 오네요.
이 경우 동적쿼리를 사용하지 않고서는 IN 조건 사용이 불가능 합니다.
조건을 brandcode IN (param_brandcode) 처럼 사용시에 동작되는 것은 다음과 같습니다.
- 원하는 것 : brandcode IN ('B001','B002')
- 실제 동작 : brandcode IN ('B001,B002')  -- 하나의 값으로 인식 --
문자열 비교 방식으로 풀 수는 있습니다만 인덱스 이용 못하죠.
- param_brandcode LIKE '%'||brandcode||'%'
- INSTR(param_brandcode, brandcode) > 0
문자열을 분리해서 IN 절에 넣는 방식도 고려해 볼 수는 있습니다.
- brandcode IN (SELECT SUBSTR(param_brandcode, (LEVEL-1)*5+1, 4) FROM dual CONNECT BY LEVEL <= (LENGTH(param_brandcode)+1)/5)
USE_CONCAT 힌트로 실행계획을 분리시켜보세요.

SELECT /*+ USE_CONCAT */ *
  FROM product
 WHERE ( (param_brandcode IS NULL) OR
         (param_brandcode IS NOT NULL
          AND brandcode IN (SELECT SUBSTR(param_brandcode, (LEVEL-1)*5+1, 4)
                              FROM dual
                             CONNECT BY LEVEL <= (LENGTH(param_brandcode)+1)/5
                            )
          )
       )
;

 


by 김첨지의럭키데이 [2019.05.14 13:12:17]

- 원하는 것 : brandcode IN ('B001','B002')
- 실제 동작 : brandcode IN ('B001,B002')  -- 하나의 값으로 인식 --

이부분은 제가 처리를 했습니다

단지 파라미터 넘어올때와 안넘어올때 분기 주는 방식이 ... or로 하기가 싫어서 ㅠ 혹시나 방법이 있나했습니다 ㅎㅎ

(param_brandcode IS NULL) OR

         (param_brandcode IS NOT NULL --> 이부분이요

ㅎㅎ  친절한 답변 감사드립니다


by 마농 [2019.05.14 13:31:28]

"이부분은 제가 처리를 했습니다" 라고 하셨는데요?
동적 쿼리를 사용하셨다는 의미인가요?
동적 쿼리를 사용했다면? 조건절 자체도 동적으로 붙이시면 되는데요?


by 김첨지의럭키데이 [2019.05.14 14:03:20]

동적쿼리로 사용안하고 

BRANDCODE IN (SELECT regexp_substr(UPPER(''),'[^/]+', 1, level) from dual  connect by regexp_substr(UPPER(''), '[^/]+', 1, level) is not null )

 

이 방법으로 했습니다 오라클을 만진지 얼마 안되서 여기저기 찾아가면서 했습니다 ㅠ

마농님이 말씀해주신 

brandcode IN (SELECT SUBSTR(param_brandcode, (LEVEL-1)*5+1, 4)

                              FROM dual

                             CONNECT BY LEVEL <= (LENGTH(param_brandcode)+1)/5 

이방법이랑 비슷하겠군요


by 마농 [2019.05.14 14:08:38]

우선 두가지 쿼리를 분리시켜 실행해 보시고 실행계획 확인해 보세요.
조건 없을 때 풀스캔, 조건 있을 때 인덱스 스캔 잘 타는지 각각 확인하시고.
위에 언급한 USE_CONCAT 힌트 사용해서 적용해 보세요.


by 김첨지의럭키데이 [2019.05.14 14:16:02]

넵 답변감사드립니다


by 이준환 [2019.05.14 16:21:11]

WHERE BRANDCODE IN ('B001', 'B002', NVL2(PARAM_BRANDCODE, NULL, BRANDCODE))

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