테이블
: 영속적 데이터 저장뷰
: 영속적이지만 데이터 저장 X, 접근 마다 Select 구문 실행서브쿼리
: 비영속적인 생존 기간이 SQL 구문 실행 중으로 한정연산비용 추가
서브쿼리 접근 마다 SELECT 구문 실행
해서 데이터 만들어야 함데이터 I/O 비용 발생
최적화 받을 수 없음
서브쿼리
사용 코드 → Bad
가독성 나쁨
성능 나쁨
- 서브쿼리는 대부분 일시적 영역(메모리 or 디스크)에 확보되므로 오버헤드 발생
- 서브쿼리는 메타정보(인덱스, 제약조건)을 가지지 않기 때문에 최적화 X
- 결합 필요하기 때문에 비용 높고, 실행계획 변동 리스크 발생
- 테이블 스캔 2회 필요
select r.cust_id, r1.seq, r1.price
from receipts r1
inner join
(select cust_id, min(seq) as min_seq
from receipts
group by cust_id) r2
on r1.cust_id = r2.cust_id and r1.seq = r2.min_seq;
상관 서브쿼리
사용 코드 → Bad
테이블 스캔 2회 필요
select cust_id, seq, price
from receipts r1
where seq = (select min(seq)
from receipts r2
where r1.cust_id = r2.cust_id);
윈도우 함수
로 결합 제거 → Good
SQL 튜닝에서 가장 중요한 I/O 줄이기
위해 윈도우 함수 적용
윈도우 함수 사용으로 정렬이 실행계획에 추가되었긴 하지만, 튜닝에서 가장 중요한 건 I/O 줄이기
select cust_id, seq, price
from (select cust_id, seq, price
row_number()
over (partition by cust_id
order by seq) as row_seq
from receipts) work
where work.row_seq = 1;
알고리즘 변동 리스크
환경 요인에 의한 지연 리스크
실행 계획이 단순할 수록 안정적 성능
결과 뿐만 아니라 성능도 보장
생각의 보조 도구
select c.co_cd, max(c.distinct), sum(emp_nbr) as sum_emp
from companies c inner join shops s on c.co_cd = s.co_cd
where main_flg = 'Y'
group by c.co_id;
I/O 비용
을 감소시킬 수 있음select c.co_cd, c.district.sum_emp
from companies c
inner join (select co_cd, sum(emp_nbr) as sum_emp
from shops
where main_flg = 'Y'
group by co_cd) csum
on c.co_cd = csum.co_cd;
I/O 지분 절대적
서브쿼리 + 결합 → 윈도우 함수
가 답이다