DB

[MySQL] 서브쿼리 vs JOIN 성능 비교와 실행계획으로 분석하기

인생아 2025. 7. 4. 12:47
반응형

MySQL 쿼리를 작성할 때 서브쿼리로 할까? 조인으로 할까? 이 고민, 정말 많이 해봤을 것이다. 둘 다 같은 결과를 내지만, 성능은 상황에 따라 천차만별이다. 어떤 경우에 서브쿼리가 유리하고, 어떤 경우에 JOIN이 성능상 우위를 가지는지 실행계획을 활용해 명확히 분석해보자.

📌 기본 구조 비교

✅ 서브쿼리 예시

SELECT name
FROM users
WHERE id IN (
  SELECT user_id FROM orders WHERE amount > 5000
);

✅ JOIN 예시

SELECT u.name
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 5000;

결과는 같지만 성능은 다를 수 있다.

반응형

🔍 실행계획(EXPLAIN) 비교 분석

🔬 서브쿼리 실행계획

EXPLAIN
SELECT name
FROM users
WHERE id IN (
  SELECT user_id FROM orders WHERE amount > 5000
);
  • users 테이블을 탐색하면서 서브쿼리를 반복적으로 수행 (비효율적)
  • MySQL 5.x에서는 특히 상관 서브쿼리일 경우 Nested Loop로 처리되어 매우 느릴 수 있음

🔬 JOIN 실행계획

EXPLAIN
SELECT u.name
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 5000;
  • orders.amount에 인덱스가 있으면 range scan 적용
  • users와 orders 조인을 통해 한 번에 결과 집합 생성

📈 비교 요약

항목 서브쿼리 방식 JOIN 방식
구조 반복 실행 병합 수행
성능 느림 (특히 많은 행일 때) 빠름
확장성 복잡한 로직에 유리 구조가 직관적
인덱스 활용 제약 있음 인덱스 효율적으로 활용 가능
 
반응형

🧠 실무 팁: 언제 서브쿼리? 언제 JOIN?

상황 추천 방식 설명
단순 포함 조건 JOIN IN → JOIN 변환 시 빠름
복잡한 조건 필터링 서브쿼리 집계나 필터가 많을 때 명확함
뷰(View) 기반 필터링 JOIN 실행 최적화 쉬움
외부 SELECT 참조가 필요한 경우 서브쿼리 상관 서브쿼리 사용 가능
 

💡 상관 서브쿼리는 조심해야 한다

다음과 같은 형태는 성능 병목이 생길 수 있다:

SELECT name,
       (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS order_count
FROM users u;

위 쿼리는 users의 모든 row에 대해 orders 테이블을 반복 검색한다. 대량의 데이터가 있을 경우 매우 느려질 수 있다. 이럴 때는 다음처럼 JOIN + GROUP BY로 리팩토링하자:

SELECT u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id;

📌 결론

  • 성능이 중요하면 JOIN이 기본값
  • 간단한 조건 필터도 JOIN이 빠름
  • 상관 서브쿼리는 최대한 피하기
  • 필요시 EXPLAIN으로 직접 실행계획 확인

📎 참고 공식문서

MySQL Subquery Optimization:
https://dev.mysql.com/doc/refman/8.0/en/subquery-optimization.html

MySQL Join Optimization:
https://dev.mysql.com/doc/refman/8.0/en/join-optimization.html

반응형