VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
서브쿼리의 종류
비상관 서브쿼리는 한 번 실행되고 그 결과를 외부 쿼리가 사용합니다:EXPLAIN을 확인하세요.
IN 대 EXISTS 대 JOIN
이 3가지 패턴은 종종 같은 문제를 해결합니다:
MySQL 옵티마이저는
IN (subquery)를 내부적으로 세미 조인으로 다시 쓰는 경우가 많으므로, 성능 차이는 무시할 만한 경우가 잦습니다. 서브쿼리 결과 집합이 크면 EXISTS나 JOIN이 더 안정적입니다.
NOT IN의 NULL 문제
NOT IN은 서브쿼리가 NULL을 하나라도 반환하면 예상 밖으로 동작합니다:
orders.customer_id에 NULL 행이 하나라도 있으면 NOT IN 전체가 빈 결과를 반환합니다. 이것은 올바른 SQL 동작입니다 — NULL은 알 수 없는 값이므로, NOT IN (NULL, 1, 2)는 모든 비교에서 UNKNOWN입니다. 대신 NOT EXISTS를 사용하세요:
FROM의 서브쿼리(파생 테이블)
FROM 절의 서브쿼리는 파생 테이블을 만듭니다:
성능 고려 사항
MySQL 옵티마이저는 많은 서브쿼리 패턴을 다시 씁니다. 직접 최적화하기 전에:- 서브쿼리 버전과 JOIN 버전 모두에
EXPLAIN을 실행해서 MySQL이 실제로 무엇을 실행하는지 확인하세요 - 조인/상관 열에 인덱스가 있는지 확인하세요 — 보통 그것이 병목입니다
EXPLAIN이 실행 계획에서 큰 차이를 보일 때만 다시 쓰세요
자주 묻는 질문
JOIN은 항상 서브쿼리보다 빠른가요?
꼭 그렇지는 않습니다. MySQL 8.0의 옵티마이저는 많은 경우IN (subquery)를 세미 조인으로 다시 써서 명시적 JOIN과 같은 실행 계획을 만듭니다. 한 형태가 항상 더 빠르다고 가정하지 말고 EXPLAIN으로 측정하세요.
IN 대신 EXISTS를 언제 사용해야 하나요?
일치하는 데이터가 무엇인지가 아니라 일치가 존재하는지만 중요할 때, 서브쿼리가 NULL을 반환할 수 있을 때, 또는 서브쿼리가 큰 결과 집합을 반환할 때EXISTS를 사용하세요. EXISTS는 첫 번째 일치에서 단락 평가하고, IN은 전체 목록을 만들어야 합니다.
세미 조인이 무엇인가요?
세미 조인은 오른쪽에 일치하는 행이 하나 이상 있는 왼쪽 테이블의 행을 반환하되, 여러 일치에 대해 왼쪽 테이블 행을 중복해서 만들지 않습니다. MySQL 옵티마이저는IN (subquery)와 EXISTS를 효율적으로 실행하기 위해 내부적으로 세미 조인을 사용합니다. SQL에서 세미 조인을 직접 쓸 수는 없지만, EXISTS와 IN (subquery) 모두 옵티마이저가 세미 조인을 고려하게 만듭니다.
문제 해결
함께 보기
- MySQL JOIN 성능과 흔한 실수 — 이 비교에서 조인 쪽을 느리게 만드는 것
- MySQL CTE가 파생 테이블보다 나을 때 — 깊이 중첩된 서브쿼리의 더 깔끔한 대안
- MySQL 서브쿼리와 상관 서브쿼리 — 서브쿼리 작성법에 대한 튜토리얼 수업
- MySQL EXISTS — 행을 결코 곱하지 않는 형태