...
EXISTS 연산자
서브쿼리가 반화나는 결과값이 있는지를 조사한다.
단지 반환된 행이 있는지 없는지만 보고 값이 있으면 참 없으면 거짓을 반환한다.
- 한 테이블이 다른 테이블과 외래키(FK)와 같은 관계가 있을 때 유용
- 조건에 해당하는 ROW의 존재 유무와 이후 더 수행하지 않음 (지연 평가 원리 이기 때문에 성능이 좋다)
- 일반적으로 SELECT절까지 가지 않기에 IN에 비해 속도나 성능면에서 더 좋음
- 반대로 조건에 맞지 않는 ROW만 추출하고 싶으면 NOT EXISTS
- 쿼리 순서 : 메인 쿼리 → EXISTS 쿼리
Q. 주문한 적이 있는(주문이 존재하는) 사용자를 알고 싶은 경우
SELECT * FROM customers
WHERE EXISTS (
SELECT *
FROM orders
WHERE orders.c_id = customers.c_id
);
서브쿼리 내에서 부모쿼리의 필드를 사용할 수 있다.
마치 JAVA의 자식클래스가 부모클래스의 인스턴스를 사용할수 있는 것처럼 상속 개념이라 생각하면 된다. 연관 서브쿼리라고 한다.
이처럼 서브쿼리에서 메인쿼리 테이블을 활용하는 형태를 연관 서브쿼리라고 한다.
EXISTS 다음으로 오는 SELECT에서 * 대신 아무거나(1, ‘aa’, …) 입력해도 상관없다.
EXISTS는 조건이 맞는 지에 대한 TRUE / FALSE만 확인하기 때문이다. 만족하는 결과가 최소 하나가 나오면 바로 TRUE로 판단한다.
즉 customers 테이블의 c_id를 EXISTS 서브쿼리에 대입했을 때 값이 존재하면, 해당 레코드들을 모아 띄운다 라고 이해하면 된다.
NOT EXISTS 연산자
orders 테이블에는 customers 테이블에 존재하지 않는 고객 ID가 존재한다.
이 필드는 NOT EXISTS를 사용하면 알아낼 수 있다.
즉, 조건에 맞지않는 레코드만 추출하는 옵션이라 볼 수 있다.
SELECT *
FROM orders
WHERE NOT EXISTS (SELECT * FROM customers WHERE customers.c_id = orders.c_id);
EXISTS vs IN 연산자 차이
EXISTS와 IN은 둘다 WHERE절에서 사용되며, 조건에 따라 데이터를 걸러내어 결과를 조회할 때 사용되는 공통점을 가지고 있다.
서브쿼리 IN 연산자
- 집합 내부에 값이 존재하는지 여부 확인
- 조건에 해당하는 ROW의 컬럼 비교하여 체크
- SELECT절에서 조회한 컬럼 값으로 비교하여 EXISTS에 비해 성능 떨어짐
- 쿼리 순서 : IN 쿼리 → 메인 쿼리
-- IN
SELECT *
FROM customers
WHERE c_id IN ( SELECT DISTINCT c_id FROM orders);
EXISTS vs JOIN 성능 비교
EXISTS 대신 JOIN을 활용하여 역시 같은 결과를 얻을 수도 있다.
다음과 같이 샘플 테이블이 있다고 가정하자
INNER JOIN
select dept_id, dept_name, emp_id
from 부서 inner join 사원
on 부서.dept_id = 사원.dept_id
INNER JOIN (중복 제거)
단순히 조인했더니 중복된 레코드들이 나온다. DISTINCT로 중복을 제거한다.
select distinct dept_id, dept_name, emp_id
from 부서 inner join 사원
on 부서.dept_id = 사원.dept_id
하지만 이렇게 하면 임시 데이터에 DISTINCT 연산 자체가 꽤나 무거운 작접이며, 출력결과보다 많은 임시데이터가 생성되고 되고 그 레코드들에 대해 JOIN 연산을 해야되는 단점을 안고 있다.
서브쿼리 EXISTS
EXISTS의 경우는 inner query를 만족하는 레코드를 처음 만나는 순간 EXISTS가 true이므로 inner query를 더 이상 평가 하지 않는다. (지연 평가 원리)
이 점이 INNER JOIN과 EXISTS의 큰 차이이며 성능의 차이를 보인다.
select dept_id, dept_name
from 부서
where exists ( select 1 from 사원 where 사원.dept_id = 부서.dept_id )
-- 부서의 dept_id가 사원의 dept_id에 1개라도 존재하면 true
-- 따라서 dept_id가 동일한 사원 레코드를 만나면 더이상 탐색할 필요가 없어진다. (지연 평가)
평소에는 서브 쿼리 보다는 JOIN이 속도가 빠르겠지만, 만일 위 처럼 중복된 데이터가 많을 경우 지연 평가 원리를 사용하는 서브 쿼리 EXISTS 문이 빠를수도 있다.
# 참고자료
http://jason-heo.github.io/mysql/2014/05/30/mysql-inner-join-vs-exists.html
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.