CS/Database

[MySQL] `NOT IN` vs `NOT EXISTS` 비교 및 권장 방식

clolee 2025. 5. 4. 01:16

NOT IN vs NOT EXISTS 실무 정리: 차이점, 주의사항, 권장 방식

SQL에서 "어떤 데이터가 다른 테이블에 존재하지 않을 때" 사용하는 대표적인 방법은 다음 두 가지입니다:

  • NOT IN
  • NOT EXISTS

하지만 이 두 구문은 겉보기엔 비슷해도, NULL 처리 방식과 실무 안전성 측면에서 큰 차이가 있습니다.


✅ 1. 기본 사용법 비교

🔹 NOT IN

SELECT *
FROM members
WHERE id NOT IN (SELECT member_id FROM ads);
  • id 컬럼 값이 ads.member_id 리스트에 없을 경우만 선택
  • 비교 대상 컬럼이 반드시 필요함 (컬럼 NOT IN (리스트) 형태)

🔹 NOT EXISTS

SELECT *
FROM members m
WHERE NOT EXISTS (
    SELECT 1
    FROM ads a
    WHERE a.member_id = m.id
);
  • ads 테이블에 해당 조건(a.member_id = m.id)을 만족하는 행이 없을 경우 선택
  • 행의 존재 여부만 판단, 비교 컬럼 없이도 사용 가능

⚠️ 2. 주의할 점: NULL이 있을 경우 NOT IN은 위험

📌 문제 상황

SELECT *
FROM members
WHERE id NOT IN (SELECT member_id FROM ads);

→ 만약 ads.member_id 컬럼에 NULL 값이 1개라도 있으면 전체 결과가 무효화됩니다.

  • id NOT IN (...) 안에 NULL이 포함되면 항상 FALSE 또는 UNKNOWN
  • 즉, 모든 결과가 누락될 수 있음

✅ 현재 테이블 상황: 안전한 예외

본 사례에서는 ads.member_id는 FOREIGN KEY로 정의되어 있고 NOT NULL이기 때문에 NOT IN 사용이 안전합니다.
그러나 대부분의 실무 환경에서는 데이터가 완전하다는 보장이 없기 때문에 위험합니다.


✅ 3. 실무 권장 방식: NOT EXISTS

SELECT *
FROM members m
WHERE NOT EXISTS (
    SELECT 1
    FROM ads a
    WHERE a.member_id = m.id
);
  • NULL 값에 안전하며
  • 쿼리 옵티마이저가 인덱스를 효율적으로 사용할 수 있음
  • 대용량 데이터에서도 일반적으로 성능이 더 우수함

✅ 4. 비교 정리표

항목 NOT IN NOT EXISTS
WHERE 뒤에 바로 사용 가능
비교 대상 컬럼 필요 ✅ 반드시 필요 ❌ 조건절로 비교
NULL 처리 ⚠️ 위험 (결과 전체 누락 가능) ✅ 안전
의미 "리스트에 없다" "해당 행이 존재하지 않는다"
인덱스 활용 제한적 최적화 잘 됨
실무 추천 ⚠️ 제한적 사용 ✅ 적극 추천

✅ 5. 결론 및 실무 팁

  • 데이터 무결성이 100% 확실할 경우: NOT IN도 사용 가능
  • 그 외 대부분의 상황: NOT EXISTS를 기본 선택하는 것이 안전하고 유지보수에도 유리
  • 대량 조인 시에도 NOT EXISTS가 더 성능 좋은 경우가 많음

이 글은 실무 SQL 작성 시 JOIN이나 필터링 로직을 짤 때 안전성과 정확도를 높이는 데 도움이 됩니다.