서브쿼리를 RIGHT JOIN으로 변환하기
SQL을 작성하다 보면 NOT IN 연산자를 사용한 서브쿼리를 만나게 됩니다. 이러한 서브쿼리는 성능상 비효율적일 수 있기 때문에, RIGHT JOIN으로 변환하면 더 나은 결과를 얻을 수 있습니다. 이번 글에서는 실제 예제 데이터를 통해 변환 과정을 단계별로 살펴보겠습니다.
예제 테이블 준비
설명을 돕기 위해 아래 두 개의 테이블을 사용합니다.
mysql> Select * from Customers; +-------------+----------+ | Customer_Id | Name | +-------------+----------+ | 1 | Rahul | | 2 | Yashpal | | 3 | Gaurav | | 4 | Virender | +-------------+----------+ 4 rows in set (0.00 sec) mysql> Select * from Reserve; +------+------------+ | ID | Day | +------+------------+ | 1 | 2017-12-30 | | 2 | 2017-12-28 | | 2 | 2017-12-25 | | 1 | 2017-12-24 | | 3 | 2017-12-26 | +------+------------+ 5 rows in set (0.00 sec)
Customers 테이블은 고객 정보를 담고 있고, Reserve 테이블은 차량 예약 기록을 저장하고 있습니다.
서브쿼리로 작성한 기존 쿼리
먼저, 차량을 한 번도 예약하지 않은 고객의 이름을 찾는 서브쿼리입니다.
mysql> Select Name from customers where customer_id NOT IN (Select id From reserve); +----------+ | Name | +----------+ | Virender | +----------+ 1 row in set (0.00 sec)
이 쿼리는 customer_id가 Reserve 테이블의 id 목록에 포함되지 않은 고객, 즉 Virender만 반환합니다.
RIGHT JOIN으로 변환하는 3단계 방법
위의 서브쿼리는 다음 세 단계를 거쳐 RIGHT JOIN으로 변환할 수 있습니다.
- 테이블 위치 변경: 서브쿼리에 언급된 'Customers' 테이블을 FROM 절로 옮기고, RIGHT JOIN을 사용해 'Reserve' 테이블과 조인합니다.
- IN 표현식 변환: WHERE 절에서 customer_id 열을 서브쿼리가 반환한 id들과 비교하고 있으므로, IN 표현식을 FROM 절에 있는 두 테이블의 id 열 간 명시적인 직접 비교(
ON customer_id = Id)로 바꿉니다. - NULL 조건 추가: WHERE 절에서 'Reserve' 테이블의 값이 NULL인 행만 출력하도록 제한합니다. 매칭되지 않은 고객은 Reserve 쪽 컬럼이 NULL이 되기 때문입니다.
변환된 최종 쿼리
mysql> SELECT Name from reserve RIGHT JOIN customers ON customer_id = Id WHERE Id IS NULL; +----------+ | Name | +----------+ | Virender | +----------+ 1 row in set (0.00 sec)
결과는 서브쿼리 버전과 동일하게 Virender 하나만 반환됩니다.
마무리 정리
핵심 원리는 다음과 같습니다. RIGHT JOIN은 오른쪽 테이블(Customers)의 모든 행을 유지하면서, 왼쪽 테이블(Reserve)에 매칭되는 행이 없으면 해당 컬럼을 NULL로 채웁니다. 따라서 WHERE Id IS NULL 조건을 추가하면 예약 기록이 없는 고객만 정확히 필터링할 수 있습니다. 대용량 데이터에서는 NOT IN보다 JOIN 방식이 인덱스 활용 측면에서 더 유리한 경우가 많으므로, 상황에 맞게 활용해 보시기 바랍니다.