MySQL SELECT 문을 다루면서 자주 마주치는 조건절이 있습니다. 바로 EXISTS와 IN 조건절입니다. 이 두 문법은 서브쿼리와 함께 많이 사용되며, 조건에 따라 행을 필터링하는 데 매우 강력한 도구입니다. 하지만 상황에 따라 성능과 결과가 달라질 수 있으므로, 그 차이를 명확히 이해하고 사용하는 것이 중요합니다.

✅ EXISTS란?
EXISTS는 서브쿼리의 결과가 존재하는지 여부를 평가합니다.
즉, 서브쿼리에서 하나라도 결과가 존재하면 TRUE, 결과가 없으면 FALSE를 반환합니다.
SELECT name
FROM employees e
WHERE EXISTS (
SELECT 1
FROM departments d
WHERE d.manager_id = e.id
);
🔍 설명: 위 쿼리는 employees 테이블에서 departments의 manager_id로 등록된 직원만 조회합니다. EXISTS는 결과 유무만 판단하므로 SELECT 1처럼 아무 컬럼이나 써도 상관없습니다.
✅ IN이란?
IN 조건절은 지정한 목록(list)에 값이 존재하는지를 판단합니다. 서브쿼리와 결합하면 특정 컬럼 값이 서브쿼리 결과 안에 존재하는지 확인할 수 있습니다.
SELECT name
FROM employees
WHERE id IN (
SELECT manager_id
FROM departments
);
🔍 설명: 위 쿼리는 departments 테이블의 manager_id에 포함된 직원들을 조회합니다.
🧐 EXISTS vs IN 성능 차이
| 비교 항목 | EXISTS | IN |
| 내부 동작 방식 | 서브쿼리 결과 존재 여부만 판단 | 서브쿼리 전체 결과를 메모리에 로딩함 |
| NULL 처리 | 서브쿼리에 NULL이 있어도 문제없음 | 서브쿼리 결과에 NULL이 있으면 결과 영향 |
| 적합한 상황 | 큰 서브쿼리 결과에 적합 | 작은 리스트 필터링에 적합 |
💡 실전 팁:
- 서브쿼리 결과가 크면 EXISTS를 사용하는 것이 효율적입니다.
- 고정된 목록 필터링에는 IN이 더 간단하고 직관적입니다.
💡 실전 예제: 고객과 주문 테이블
아래는 customers와 orders 테이블이 있다고 가정하고, 다양한 쿼리 예제를 만들어봅니다.
1. EXISTS 예제 – 주문한 고객만 조회
SELECT c.name
FROM customers c
WHERE EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
2. IN 예제 – 주문한 고객만 조회
SELECT name
FROM customers
WHERE id IN (
SELECT customer_id
FROM orders
);
✔️ 두 쿼리는 동일한 결과를 출력하지만, 서브쿼리 결과가 매우 많다면 EXISTS가 더 효율적입니다.
⛔ IN 사용 시 주의사항: NULL
SELECT name
FROM customers
WHERE id IN (
SELECT customer_id
FROM orders
UNION
SELECT NULL
);
이 경우 id IN (...) 조건에 NULL이 포함되면, 예상치 못한 결과 누락이 발생할 수 있습니다.
NULL 값 필터링이 필요한 경우 EXISTS 사용을 고려하세요.
🔍 EXISTS를 활용한 NOT EXISTS 예제
SELECT name
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.id
);
이 쿼리는 주문을 한 번도 하지 않은 고객을 조회합니다.
IN으로 표현하면 복잡해지지만, NOT EXISTS는 간결하게 조건을 걸 수 있는 장점이 있습니다.
💪 EXISTS와 IN 조건절 성능 최적화 팁
- 서브쿼리 안에 인덱스를 사용하도록 유도하세요.
- JOIN으로 변경 가능하다면 JOIN도 고려하세요.
- MySQL 5.6 이상부터는 서브쿼리 최적화가 더 나아졌지만, 여전히 EXISTS가 더 빠른 경우가 많습니다.
📚 참고: 공식 가이드 문서
- MySQL EXISTS 설명: https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
- MySQL IN 조건절: https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_in
'DB' 카테고리의 다른 글
| [MySQL] SELECT FOR UPDATE 완벽 가이드 – 동시성 제어의 핵심 키워드 (0) | 2025.06.30 |
|---|---|
| [MySQL] JSON 컬럼 SELECT 조회 완벽 가이드 (0) | 2025.06.26 |
| [MySQL] LIKE와 REGEXP 차이부터 고급 패턴 검색까지 완벽 정리 (0) | 2025.06.26 |
| [MySQL] IS NULL과 IS NOT NULL 완전 정복! 조건절로 놓치지 말아야 할 핵심 포인트 (2) | 2025.06.26 |
| [MySQL] SELECT + 서브쿼리 활용법 (쿼리 안에 쿼리) (0) | 2025.06.26 |
| [MySQL] SELECT JOIN 완벽 정리 – INNER JOIN, LEFT JOIN, RIGHT JOIN 차이와 실전 예제 (0) | 2025.06.25 |
| [MySQL] SELECT + DATE_FORMAT / NOW() 함수 완벽 정리(날짜포맷, 현재시간) (0) | 2025.06.25 |
| [MySQL] SELECT CASE / IF 조건 분기 (쿼리 조건문 활용) (0) | 2025.06.25 |