티스토리 뷰
SQL을 공부하다 보면 EXISTS 와 IN 은 거의 반드시 만나게 됩니다.
둘 다 비슷해 보이지만, 실무에서는 성능 차이 때문에 신경 써야 하는 경우가 꽤 많습니다. 특히 데이터 양이 많아지면 “둘 중 아무거나 써도 되겠지”가 아니라, 어떤 상황에서 무엇을 쓰는 게 더 적절한지 판단하는 게 중요해집니다.
이번 글에서는 EXISTS 와 IN 의 차이, 성능 비교 포인트, 그리고 실무에서 어떤 기준으로 선택하면 좋은지 쉽게 정리해보겠습니다.
먼저 예시부터 보겠습니다.
SELECT *
FROM orders o
WHERE o.customer_id IN (
SELECT c.id
FROM customer c
WHERE c.status = 'ACTIVE'
);
이 쿼리는 활성 고객의 주문만 조회하는 예시입니다.
비슷한 의미를 EXISTS 로 바꾸면 이렇게 쓸 수 있습니다.
SELECT *
FROM orders o
WHERE EXISTS (
SELECT 1
FROM customer c
WHERE c.id = o.customer_id
AND c.status = 'ACTIVE'
);
둘 다 결과는 비슷할 수 있지만, 해석 방식은 다릅니다.
IN→ 특정 값이 집합 안에 포함되는지 확인EXISTS→ 조건을 만족하는 행이 존재하는지 확인
예를 들어 특정 상태 코드만 조회하는 경우는 IN 이 아주 자연스럽습니다.
SELECT *
FROM orders
WHERE status IN ('READY', 'PAID', 'SHIPPED');
이건 서브쿼리도 아니고, 그냥 값 목록 비교이기 때문에 IN 이 훨씬 읽기 쉽습니다.
또 서브쿼리라도 결과 건수가 매우 작고 단순하면 IN 이 가독성 면에서 좋을 수 있습니다.
EXISTS 는 서브쿼리 안에서 조건을 만족하는 행을 찾으면, 그 이후를 다 보지 않고 빠르게 판단할 수 있는 형태로 최적화되는 경우가 많습니다.
예를 들어 주문이 있는 고객만 찾고 싶다면:
SELECT *
FROM customer c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
이 경우 핵심은 주문 상세값이 아니라, 그 고객에게 주문이 하나라도 있느냐 입니다.
이럴 때는 IN 보다 EXISTS 가 의도도 더 명확하고, 실행계획상 유리한 경우가 많습니다.
많이 오해하는 부분이 바로 이것입니다.
EXISTS가 무조건 빠르다IN은 무조건 느리다
이렇게 외우면 안 됩니다.
실제 성능은 아래 요소에 따라 달라집니다.
- 서브쿼리 결과 건수
- 인덱스 유무
- 상관 서브쿼리 여부
- 옵티마이저가 내부적으로 어떻게 변환했는지
- DBMS 종류(MySQL, Oracle, PostgreSQL 등)
즉, 중요한 건 문법 이름보다 실행계획이 실제로 어떻게 잡히는가 입니다.
1) 서브쿼리 결과가 매우 클 때
IN 대상이 되는 결과 집합이 매우 크면 부담이 커질 수 있습니다. 이럴 때는 EXISTS 가 더 유리하게 보이는 경우가 많습니다.
2) 존재 여부만 중요할 때
실제로 필요한 건 “있다 / 없다” 뿐인데 값 목록 비교처럼 풀어 쓰면 비효율적일 수 있습니다.
3) 인덱스가 잘 잡혀 있을 때
EXISTS 안의 조인 조건 컬럼에 인덱스가 있으면 빠르게 존재 여부를 판단하기 좋습니다.
4) 옵티마이저가 내부적으로 세미조인(Semi Join) 형태로 최적화할 때
DBMS에 따라 IN 과 EXISTS 가 비슷하게 최적화되기도 합니다. 그래서 실제로는 생각보다 큰 차이가 안 날 수도 있습니다.
| 구분 | IN | EXISTS |
|---|---|---|
| 의미 | 값이 집합 안에 포함되는지 확인 | 조건 만족 행이 존재하는지 확인 |
| 가독성 | 값 목록 비교에 직관적 | 존재 여부 판단에 직관적 |
| 자주 유리한 상황 | 작은 목록, 단순 비교 | 큰 데이터, 존재 여부 확인 |
| 실무 팁 | 간단하면 IN도 충분 | 성능 이슈 있으면 EXISTS 우선 검토 |
특히 NOT IN 은 NULL 이 섞이면 예상과 다른 결과가 나올 수 있어서 주의해야 합니다.
예를 들어 서브쿼리 결과 안에 NULL 이 포함되면, NOT IN 비교가 의도대로 동작하지 않는 경우가 있습니다.
이럴 때는 NOT EXISTS 가 더 안전한 선택이 되는 경우가 많습니다.
SELECT *
FROM customer c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
실무에서는 보통 이렇게 생각하면 쉽습니다.
- 값 목록 비교가 핵심이면
IN - 존재 여부 판단이 핵심이면
EXISTS - 서브쿼리 결과가 크다면
EXISTS우선 검토 - NULL 이 걸릴 수 있는 부정 조건이면
NOT EXISTS우선 검토 - 최종 판단은 반드시 실행계획으로 확인
실무 SQL은 문법을 외우는 것보다, 이 쿼리가 값을 비교하는지 존재를 확인하는지를 먼저 구분하는 습관이 더 중요합니다.
'IT > SQL·DB' 카테고리의 다른 글
| MySQL vs PostgreSQL 차이 | 어떤 걸 선택해야 할까 쉽게 정리 (0) | 2026.03.26 |
|---|---|
| 서브쿼리 vs JOIN 무엇이 더 빠를까? | 성능 비교와 사용 기준 정리 (5) | 2026.03.26 |
| 인덱스를 걸었는데도 느린 이유 7가지 | 실무에서 자주 틀리는 포인트 (0) | 2026.03.25 |
| 트랜잭션(Transaction)이란? ACID와 격리수준까지 쉽게 이해하기 (0) | 2026.03.25 |
| 인덱스란 무엇인가? 초보도 이해하는 원리 + 성능 차이 (0) | 2026.03.25 |

