본문 바로가기

SQL 튜닝의 시작

[ SQL ] 서브쿼리를 활용한 SQL 성능개선

1. 비효율적인 MINUS 대신 NOT EXISTS를 사용하기

MINUS : 어느 한 집합에 있는 데이터 중 다른 집합에 존재하지 않는 데이터를 추출하는 방식

  • MINUS를 사용한 SQL이 성능 문제가 발생할 경우, SQL을 변경하지 않고, 성능을 개선하기가 쉽지않다.
  • 차 집합을 추출하기 위해서는 MINUS 연산보다 NOT EXISTS 가 더 효율적이다.

ex )

--MINUS
select...
from A MINUS 
select from B 

--NOT EXISTS
select... 
from A 
where NOT EXISTS (
select... 
from B where B.XX = A.XX )

위와 같은 2개의 쿼리문 실행시,

MINUS의 경우

  • 테이블 A 데이터 추출 -> 추출된 데이터 SORT 연산 -> 테이블 B 데이터 추출 -> 추출된 데이터 SORT 연산 -> 추출된 두 개의 데이터 비교 후 최종 데이터 추출
  • 수행순서가 변경 불가능하다.
  • 성능면에서 떨어지게된다.

NOT EXISTS의 경우

  • 데이블 A 데이터 추출 -> 추출한 데이터와 서브 쿼리 테이블 B 데이터와 비교 후 최종 데이터 추출
  • 수행순서 변경이 가능하다.
  • 성능면에서 비교적 유리하다.

(1) MINUS를 사용한 SQL에서 발생하는 성능 문제

  1. 비교 대상 테이블에서 데이터 추출하는 방식이 비효율 (Full Table Scan) 인데도 불구하고조회 조건이 없어 개선을 하기 힘들다.
  2. 비교 대상 테이블에서 많은 데이터가 추출되면 정렬 작업이 과다하게 발생한다.

(2) NOT EXISTS 를 이용하였을때의 위험성

  • Select 절에 나열된 컬럼의 조합이 Unique 하지 않다면, NOT EXISTS를 활용 시 중복된 값이 추출될 가능성이 있다.
  • 중복된 값이 나올수 있기때문에 DISTINCT 처리를 하게 되는 경우가 발생한다.
  • MINUS를 무조건 NOT EXISTS로 변경한다면, 성능은 개선되겠지만 데이터 정합성이 훼손되는 현상이 발생할 수 있다.
  • 그러므로 MINUS 대신 NOT EXISTS 를 사용하여 SQL을 작성할 경우 DISTINCT를 무조건 적용하기 보다는, Select 절에 나열된 컬럼 조합이 Unique 한지 먼저 판단해야한다.
  • 반드시 Unique 하지 않은 경우에만 DISTINCT를 사용할것

2. 조인 대신 서브쿼리를 활용하기

  • 조인 사용시에 Unique 한 컬럼을 조인하여 조회할 시 비용이 크게 들지않지만,
    Unique한 컬럼과 그렇지 않은 컬럼을 조인하여 조회하게되면, 비용이 커지게 된다.
  • 해결방법으로는 조인순서 변경이있지만, 불가능하다.
  • 처음부터 중복 값을 추출하지 않는다면, 조인 연결 시도횟수가 줄어들어 비효율을 개선할수있다.
  • 데이터가 급격히 증가하게 된 조인부분을 서브쿼리로 대체하여 데이터 정합성을 훼손하지않는 선에서 효율적으로 개선할수있다.
  • 단, SUM 이나 COUNT 등의 그룹 함수를 수행하는 경우는 데이터가 훼손될 수 있으므로, 데이터 정합성 체크를 필히 수행해야 한다.

3. WHERE 절의 서브쿼리를 조인으로 변경하기

  • Where 절에 서브쿼리가 많다면, 서브쿼리들이 가질 수 있는 모든 조합에 대한 Cost를 계산해야 하므로, 옵티마이저가 모든 서브쿼리를 Unnest 수행한 것과 모두 수행하지 않은 것 두가지의 Cost만 계산하게 되므로 부하가 될 수 있다.
  1. 서브쿼리로 작성된 부분을 인라인 뷰로 바꾸어 SQL을 작성하고, 추출 데이터가 중복 값을 가진 경우에는 DISTINCT를 부여해 중복을 제거
  2. 인라인 뷰로 바뀐 서브쿼리를 조인 순서를 조절하는 LEADING 힌트를 사용하여 실행계획을 제어하면 의도한 대로 SQL 수행가능