EXISTS-JOIN

sykim·2025년 8월 29일

db

목록 보기
5/7

결론부터 말씀드리면, "매번 실행되지만 JOIN보다 훨씬 효율적인 경우가 많다" 입니다.

'N번 실행'의 함정과 최적화

중첩 서브쿼리를 사용하는 EXISTS는 메인 쿼리의 행 수(N)만큼 서브쿼리가 실행되는 것이 맞습니다. 하지만 성능이 저하될 것이라는 예상은 두 가지 중요한 사실을 간과하고 있는 것이다.

  1. 'Short-Circuit' 평가: 찾으면 바로 멈춘다!
    이것이 EXISTS 성능의 가장 큰 비밀입니다.

EXISTS의 동작: 서브쿼리에서 조건을 만족하는 단 하나의 행이라도 찾으면 즉시 평가를 멈추고 TRUE를 반환한 뒤 다음 메인 쿼리 행으로 넘어갑니다. 서브쿼리 테이블을 끝까지 스캔할 필요가 전혀 없습니다.

JOIN의 동작: JOIN은 조건을 만족하는 모든 행을 찾아야 합니다. 예를 들어, 고객 한 명에게 1,000개의 주문이 있다면, JOIN은 그 1,000개의 조합을 모두 만들어 메모리에 올리려고 시도합니다.


어떤 학생이 도서관에 책을 한 권이라도 빌렸는지 확인하고 싶습니다.

EXISTS 방식: 대출 기록을 한 줄씩 보다가 그 학생 이름이 한 번이라도 나오면 "네, 빌렸네요!" 하고 확인을 끝냅니다. (매우 빠름)

JOIN 방식: 그 학생이 빌린 책 목록 전체를 찾아서 가져옵니다. (상대적으로 느림)

특히 서브쿼리의 WHERE 절에 있는 조건(o.customer_id = c.customer_id)에 인덱스(Index)가 잘 설정되어 있다면, EXISTS는 매번 실행될 때마다 인덱스를 통해 번개처럼 빠르게 단 하나의 행만 찾고 바로 종료됩니다. 따라서 N번 실행되더라도 그 각각의 실행 비용이 거의 '0'에 가깝기 때문에 전체적으로는 매우 빠릅니다.

  1. 불필요한 데이터 I/O가 없다
    EXISTS는 오직 '존재 여부'라는 TRUE/FALSE 신호만 필요합니다. 서브쿼리 테이블의 어떤 컬럼 데이터도 실제로 가져와서 조합할 필요가 없습니다. SELECT 1, SELECT '아무거나' 처럼 써도 되는 이유가 바로 이것입니다.

반면, JOIN은 두 테이블의 데이터를 실제로 결합하기 위해 양쪽 테이블에서 데이터를 읽어와야 하므로 더 많은 I/O 비용과 메모리를 사용합니다.

  1. DISTINCT나 GROUP BY 같은 추가 비용이 없다
    앞선 답변에서 설명드렸듯이, 1:N 관계에서 JOIN을 사용하면 1쪽의 데이터가 N만큼 중복되어 나타납니다. 이 중복을 제거하기 위해 SELECT DISTINCT나 GROUP BY를 추가로 사용해야 하는데, 이 작업들은 정렬(Sort)이나 해싱(Hashing)을 유발하는 매우 비싼 연산입니다.

EXISTS는 애초에 중복을 만들지 않으므로 이러한 추가 비용이 전혀 발생하지 않습니다.

결론: 언제 JOIN을 쓰고, 언제 EXISTS를 쓸까?

이 질문에 대한 답은 쿼리의 목적에 따라 명확하게 나뉩니다.

EXISTS를 써야 할 때:

다른 테이블의 데이터가 필요한 것이 아니라, 단지 특정 조건을 만족하는 데이터가 존재하는지 여부만 확인하고 싶을 때. (가장 중요한 기준)

"~한 데이터를 가진 A 테이블을 조회해줘" 와 같은 요구사항일 때.

JOIN을 써야 할 때:

SELECT 절이나 WHERE 절에서 다른 테이블의 컬럼 값을 직접 사용해야 할 때.

"A 테이블과 B 테이블의 컬럼을 합쳐서 보여줘" 와 같은 요구사항일 때.

따라서 'EXISTS는 JOIN보다 항상 느리다'는 것은 대표적인 오해 중 하나입니다. 오히려 '존재' 여부를 묻는 쿼리에서는 JOIN을 남용하는 것이 심각한 성능 저하를 일으키는 안티 패턴(Anti-Pattern)이 될 수 있습니다.

profile
공부 정리 블로그

0개의 댓글