MySQL에서 EXISTS는 쿼리가 결과를 반환했는지 여부만 확인하는 반면, IN은 하나의 값을 다른 값들과 비교할 때 사용합니다. 특히 IN은 리터럴(literal) 값을 기반으로 동작한다는 점이 특징입니다.
EXISTS와 IN의 선택 기준
핵심 원칙: 서브쿼리의 결과 집합이 매우 작을 때는 IN이 선호되며, 서브쿼리 결과가 매우 클 경우에는 EXISTS를 사용하는 것이 효율적입니다.
그 이유는 간단합니다. IN은 서브쿼리의 전체 결과를 먼저 생성한 뒤 외부 쿼리의 값과 비교하기 때문에, 결과 집합이 작을 때 빠른 성능을 보입니다. 반면 EXISTS는 조건을 만족하는 행을 하나라도 찾으면 즉시 평가를 중단하므로, 대량의 데이터를 다룰 때 유리합니다.
IN 서브쿼리 실습 예제
서브쿼리 결과가 작은 경우에 적합한 IN의 사용 예제를 살펴보겠습니다.
1. 테이블 생성
mysql> create table InSubQueryDemo
-> (
-> PNumber int,
-> PName varchar(100)
-> );
Query OK, 0 rows affected (0.60 sec)
2. 레코드 삽입
mysql> insert into InSubQueryDemo values(1,'Laptop');
Query OK, 1 row affected (0.17 sec)
mysql> insert into InSubQueryDemo values(2,'WirelessKeyboard');
Query OK, 1 row affected (0.21 sec)
mysql> insert into InSubQueryDemo values(3,'WirelessMouse');
Query OK, 1 row affected (0.12 sec)
3. 전체 레코드 조회
mysql> select * from InSubQueryDemo;
실행 결과는 다음과 같습니다.
+---------+------------------+
| PNumber | PName |
+---------+------------------+
| 1 | Laptop |
| 2 | WirelessKeyboard |
| 3 | WirelessMouse |
+---------+------------------+
3 rows in set (0.00 sec)
4. IN 서브쿼리 실행
다음은 IN 연산자에 서브쿼리를 포함하여 'PNumber' 값이 1보다 큰 레코드만 조회하는 구문입니다.
mysql> select * from InSubQueryDemo
-> where PNumber IN (select PNumber from InSubQueryDemo WHERE PNumber > 1);
실행 결과는 아래와 같습니다.
+---------+------------------+
| PNumber | PName |
+---------+------------------+
| 2 | WirelessKeyboard |
| 3 | WirelessMouse |
+---------+------------------+
2 rows in set (0.04 sec)
정리
- IN: 서브쿼리 결과가 작을 때 선호되며, 리터럴 값 목록과 비교하는 방식으로 동작합니다.
- EXISTS: 서브쿼리 결과가 클 때 유리하며, 결과의 존재 여부만 확인하고 조건 충족 시 즉시 평가를 멈춥니다.
따라서 실무에서는 서브쿼리가 반환하는 데이터의 크기를 고려하여 두 연산자 중 적절한 것을 선택하는 것이 성능 최적화의 핵심입니다.