서버 개발/프로그래머를 위한 RDBMS

서브 쿼리 활용

지노윈 2020. 5. 27. 10:54
반응형

'제공자 역할'

  • 서브 쿼리라면 먼저 수행됩니다.
  • 서브 쿼리의 결과를 메인 쿼리로 제공해주며 메인 쿼리의 인덱스로 잡혀야 겠습니다.
  • 서브 쿼리 안에 메인 쿼리의 컬럼이 없어야 합니다.

'확인자 역할'

  • 메인 쿼리가 먼저 실행되고 서브 쿼리가 실행됩니다.
  • 서브 쿼리 내에 메인 쿼리의 컬럼이 있다면 '확인자 역할'을 합니다.

 

- 잘못 사용된 예

REQT 테이블 2000만 건(월 500만건 생성)

INDEX는 cust_no + req_ym

update reqt x
  set in_amt = in_amt + @amt
where req_ym = '202005'
and custno in (select custno from cust y
               where pay_cust = @cust
               and x.custno = y.custno)

지불 고객을 찾아서 update를 하는 쿼리입니다.

서브 쿼리의 결과는 2, 3건 정도입니다. 그렇다면 이 쿼리는 순쉽간에 끝나야 합니다.

그런데 이상하게 16,000초가 걸렸습니다. 왜 일까요?

 

서브쿼리가 제공자 역할을 하길 기대하고 있으나  x.custno = y.custno 조건 때문에 확인자 역할이 되어 실행시간이 오래 걸리게 되었습니다.

확인자 역할이면 REQT 테이블이 먼저 드라이빙 되며 req_ym = '202005'는 인덱스가 없으므로 풀 테이블 스캔을 합니다.

2020년 5월 고객중 한 명을 대상으로 서브 쿼리를 실행합니다. 이렇게 500만 번을 뺑뺑이 돌면서 수행합니다.

x.custno = y.custno는 들어갈 필요가 없는 조건이며 개발자가 동일한 고객이어야 한다는 불안한 마음에 넣은 체크 조건입니다.

개발할 때는 테스트 데이터가 들어가 있었기에 의도한 대로 잘 동작한다고 생각하였지만 실제로는 그렇지 않은 예입니다.

 

- 서브 쿼리를 이용한 부분 범위 처리

다음은 전체 범위 처리입니다.

select x.col1,
  min(x.col4), min(x.col5)
from tab1 x, tab2 y
where x.col1 = y.fld1
  and x.col2 between '11' and '99'
  and y.fld3 like '202005%'
group by x.col1
having sum(y.fld4) > 0

tab2의 y.fld3 like '202005%'이 너무나 똑똑한 조건이라면,

이 조건을 제공자 역할로 서브 쿼리에 넣어 줍니다. 그러면 서브쿼리가 여전히 전체 범위 처리이지만 나머지는 부분범위 처리입니다.

select col1, col4, col5 
from tab1 x
where col1 in (select fld1
             from tab2 y
             where y.fld3 like '202005%'
             group by y.fld1
             having sum(y.fld4) > 0)
and x.col2 between '11' and '99'

또는, Tab1의 조건들이 똑똑하다면 서브쿼리를 확인자 역할로서 필터처리 합니다.

select col1, col4, col5
from tab1
where col3 between '11' and '99'
and exists(select ''
           from tab2
           and fld1 = col1
           and fld3 like '202005%'
           group by fld1, flb2
           having sum(y.fld4) > 0

 

- 길드 레이드 참가 길드 목록 조회

길드 레이드 테이블의 pk가 길드 코드 + 참가년월

길드 레이드에 참가한 길드 목록을 얻기위해 모든 길드의 길드 레이드를 모두 조인하여 distinct 합니다.

select distinct 길드명
from 길드 x, 길드레이드 y
where x.길드코드 = y.길드코드
and y.참가년월 between '202001' and '202005'

1건 이라도 있으면 더 이상 조사할 필요가 없으므로 한 로우만 처리하도록 합니다.

select 길드명
from 길드
where exists (select ''
              from 길드레이드
              where y.길드코드 = x.길드코드
              and y.참가년월 between '202001' and '202005'

 

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 게임 서버 프로그래머가 알아야 할 RDBMS

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 옵티마이저 맛보기

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 테이블 조인 하면 느리다?

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 리커시브 모델의 활용

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 아크 모델(exclusive or)에서의 주의점

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 부분범위 처리와 전체 범위처리

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 인덱스의 제대 사용하자

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - DB 옵티마이저

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - Nested Loop/Sort Merge/Hash Join

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - DB 테이블 클러스터링 팩터

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - DB 절차적 사고 VS 집합적 사고

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - SQL 집합의 가공

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - SQL IN의 특징과 IN의 활용

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 서브 쿼리 활용

[데이터베이스/게임 서버 프로그래머가 알아야 할 RDBMS] - 인라인 뷰의 활용