개요
•
서브쿼리란 SQL 내부에서 작성되는 일시적인 테이블
•
기능적 관점에서 서브쿼리와 테이블은 동일
•
비기능적인(특히 성능적인) 관점에서 서브쿼리와 테이블은 차이가 있다.
21강. 서브쿼리가 일으키는 폐해
1.
서브쿼리의 문제점
•
연산 비용 추가 - 서브쿼리는 실제 데이터를 저장하고 있지 않기 때문에 서브쿼리를 사용할 때마다 SELECT 구문이 실행된다.
•
데이터 I/O 비용 발생 - 연산 결과를 저장해야 하는데, 메모리가 부족하다면 TEMP 탈락이 발생하여 성능이 급격히 떨어질 수 있다.
•
최적화를 받을 수 없음 - 서브쿼리에는 테이블과는 달리 인덱스와 같은 메타데이터가 없기에 옵티마이저가 최적화를 할 수 없다.
2.
서브쿼리 의존증
•
다음과 같은 테이블에서 고객별 최소 순번 레코드를 구하고자 한다.
◦
구하고자 하는 레코드들
◦
이 문제에서 어려운 점은 순번의 최솟값이 고객마다 다르기 때문에, 최솟값을 동적으로 구해야 한다는 점이다.
◦
서브쿼리를 사용한 방법
→ 고객들의 최소 순번 값을 저장하는 서브쿼리를 만들고, 기존의 Receipts 테이블과 결합한다.
◦
위 쿼리의 작동 방식
◦
서브쿼리를 사용한 방식의 단점
1.
가독성이 떨어진다.
2.
성능이 나쁘다.
→ 성능이 나쁜 4가지 이유
•
윈도우 함수를 사용한 방법
◦
SQL 튜닝에서 가장 중요한 부분은 I/O를 줄이는 것이다.
→ 따라서, 우선, Receipts 테이블에 대한 접근을 1회로 줄여야 한다.
◦
ROW_NUMBER로 각 사용자의 구매 이력에 번호를 붙임으로써, seq 필드의 최솟값을 동적으로 구하기 위해서 서브쿼리를 사용해야 했던 문제를 해결하여 테이블 접근을 1회로 줄일 수 있다.
◦
또한, 윈도우 함수를 사용해서 결합을 제거함으로써 성능의 안전성도 확보할 수 있다.
3.
장기적 관점에서의 리스크 관리
•
서브쿼리와 같은 결합을 사용하는 방식은 다음과 같은 불안정 요소를 가지고 있다.
•
옵티마이저에 의해서 결합 알고리즘이 변경되면 성능이 변화될 수 있다.
•
항상 결합 키에 인덱스가 존재하지는 않으며, TEMP 탈락에 대비해 작업 메모리를 늘리는 것 또한 트레이드오프가 있다.
•
따라서, 엔지니어는 기능뿐만 아니라 성능도 고려해서 옵티마이저가 이해하기 쉬운 쿼리를 작성해야 한다.
22강. 서브쿼리 사용이 더 나은 경우
•
결합할 때는 최대한 결합 대상 레코드 수를 줄이는 것이 중요하다.
◦
1:N의 관계를 가지고 있는 회사 테이블과 사업소 테이블을 사용해서, 각 회사마다 주요 사업소의 직원 수를 구해야 한다.
1.
결합을 한 뒤에 집약하는 방법
2.
집약을 한 뒤에 결합하는 방법
◦
두 방법은 같은 결과를 내므로 기능적으로 같고, 가독성 면에서도 큰 차이가 없다.
◦
하지만, 성능에서 차이가 난다.
▪
결합 후 집약
▪
집약 후 결합
◦
결합 후 집약하는 방식은 회사 테이블과 사업소 테이블의 레코드를 모두 결합해야 하기 때문에 결합 대상 레코드는 두 테이블의 레코드 수를 더한 값이다.
◦
집약 후 결합하는 방식은 사업소 테이블을 집약하여 레코드 수가 4개로 감소했기 때문에 결합 대상 레코드가 비교적 적다.
◦
결합 대상 레코드 수에 따른 성능 차이는 테이블의 규모가 클수록 더욱 차이가 난다.
◦
단순히 결합과 집약이라는 두 연산의 순서를 바꿈으로써 쿼리의 성능을 개선할 수 있다.
요약
•
서브쿼리를 사용하지 않으면 해결할 수 없는 상황도 많기에, 무작정 서브쿼리를 사용하는 것이 안 좋은 것은 아니다.
•
하지만, 서브쿼리는 집합을 세세한 부분으로 나누고 이들을 조합해서 결과 집합을 만들어내는 BOTTOM-UP 방식이기 때문에 비절차 지향형 언어인 SQL과 지향하는 바가 다르다는 점을 고려해야 한다.
•
SQL 성능을 결정하는 요인은 I/O가 절대적이다.
→ 때문에 결합을 줄이는 것이 중요하다.
•
성능 개선을 위해서 서브쿼리와 결합을 윈도우 함수로 대체하는 것을 고려해보자
•
서브쿼리를 사용할 때는 결합 대상 레코드 수를 사전에 압축함으로써 성능을 개선할 수 있다.