EXISTS는 서브쿼리(Subquery)에 결과 행이 존재하는지를 확인하는 역할을 합니다.
EXISTS의 핵심은 서브쿼리가 반환하는 실제 데이터 값이 아니라, 결과 집합의 존재 유무(True/False) 에만 관심이 있다는 점입니다.
EXISTS의 기본 동작 원리 🧐EXISTS는 WHERE 절에서 사용되며, 다음과 같은 구조를 가집니다.
SELECT column1, column2, ...
FROM table1
WHERE EXISTS (
SELECT 1
FROM table2
WHERE condition
);
table1의 각 행을 순차적으로 읽습니다.table1의 현재 행 값을 이용하여 서브쿼리를 실행합니다. 이처럼 메인 쿼리의 값을 서브쿼리가 참조하는 것을 연관 서브쿼리(Correlated Subquery) 라고 하며, EXISTS는 대부분 이런 형태로 사용됩니다.EXISTS 조건은 TRUE가 되어 메인 쿼리의 해당 행이 결과에 포함됩니다.EXISTS 조건은 FALSE가 되어 메인 쿼리의 해당 행은 결과에서 제외됩니다.가장 중요한 특징은 "Short-circuit" 평가를 한다는 것입니다. 서브쿼리에서 조건을 만족하는 첫 번째 행을 찾는 즉시 평가를 중단하고 TRUE를 반환하므로, 불필요한 전체 테이블 스캔을 피할 수 있어 성능상 큰 이점을 가집니다.
EXISTS vs. IN vs. JOINEXISTS는 종종 IN이나 JOIN으로 대체할 수 있지만, 내부 동작 방식과 성능에서 중요한 차이가 있습니다.
EXISTS vs. IN| 구분 | EXISTS | IN |
|---|---|---|
| 동작 방식 | 메인 쿼리의 각 행에 대해 서브쿼리를 실행하여 조건 만족 여부 확인 | 서브쿼리를 먼저 실행하여 결과 리스트를 메모리에 저장 후, 메인 쿼리의 값과 비교 |
| 성능 | 서브쿼리의 결과 집합이 매우 클 때 유리 (첫 행만 찾으면 멈추므로) | 서브쿼리의 결과 집합이 작을 때 유리 |
| 서브쿼리 | SELECT 1, SELECT * 등 컬럼은 중요하지 않음 (존재 여부만 판단) | SELECT column 처럼 비교할 특정 컬럼을 명시해야 함 |
NULL 처리 | NOT EXISTS는 NULL 값에 영향을 받지 않아 직관적 | NOT IN은 서브쿼리 결과에 NULL이 포함되면 예기치 않은 결과(0개 행)를 반환할 수 있음 |
예시: 주문(Orders)이 하나라도 있는 고객(Customers)을 찾는 경우
SQL
-- EXISTS 사용 (효율적)
SELECT c.customer_name
FROM Customers c
WHERE EXISTS (
SELECT 1
FROM Orders o
WHERE o.customer_id = c.customer_id -- 연관 서브쿼리
);
-- IN 사용
SELECT c.customer_name
FROM Customers c
WHERE c.customer_id IN (
SELECT o.customer_id
FROM Orders o
);
Orders 테이블이 매우 크다면 EXISTS가 훨씬 효율적입니다.
EXISTS vs. JOINJOIN은 두 테이블을 연결하여 양쪽 테이블의 컬럼을 모두 결과로 가져올 때 사용합니다. 반면 EXISTS는 한 테이블의 데이터를 필터링하기 위해 다른 테이블의 존재 여부만 확인할 때 사용합니다.
JOIN은 1:N 관계에서 N쪽 테이블과 조인하면 1쪽 테이블의 행이 중복될 수 있지만, EXISTS는 중복을 발생시키지 않습니다. 이런 특성 때문에 EXISTS는 세미 조인(Semi Join) 역할을 수행한다고 말합니다.
예시: 주문이 있는 고객 정보 "만" 필요한 경우
SQL
-- JOIN 사용 (중복 발생 가능)
SELECT DISTINCT c.customer_id, c.customer_name -- 중복 제거를 위해 DISTINCT 필요
FROM Customers c
JOIN Orders o
ON c.customer_id = o.customer_id;
-- EXISTS 사용 (중복 없음, 더 효율적)
SELECT c.customer_id, c.customer_name
FROM Customers c
WHERE EXISTS (
SELECT 1
FROM Orders o
WHERE o.customer_id = c.customer_id
);
이 경우, 고객 정보만 필요하므로 JOIN보다 EXISTS가 더 명확하고 성능도 좋습니다.
NOT EXISTS의 활용NOT EXISTS는 서브쿼리의 결과가 존재하지 않을 때 TRUE를 반환합니다. 특정 조건을 만족하는 데이터가 없는 행을 찾을 때 매우 유용하며, 안티 세미 조인(Anti Semi Join) 역할을 합니다.
예시: 한 번도 주문한 적이 없는 고객(Customers)을 찾는 경우
SQL
SELECT c.customer_name
FROM Customers c
WHERE NOT EXISTS (
SELECT 1
FROM Orders o
WHERE o.customer_id = c.customer_id
);
이 쿼리는 LEFT JOIN과 IS NULL을 사용하는 것보다 더 직관적이고 성능이 좋은 경우가 많습니다.
정리하자면, EXISTS 절은 다음과 같은 상황에서 강력한 성능과 명확한 가독성을 제공합니다.
JOIN 사용 시 발생하는 결과 행의 중복을 피하고 싶을 때 (Semi Join)NOT EXISTS -> Anti Semi Join)