쿼리를 작성하다 보니 EXISTS와 IN 중 어느 걸 써야 더 효율적일지 궁금해졌다. 오늘은 이 둘의 동작방식과 어떤 상황에서 어떤 연산자를 사용해야 더 효율적일지 알아보자.
EXISTS와 IN은 WHERE절에 사용되며, 조건에 따라 데이터를 걸러내어 결과를 조회할 때 사용된다.
EXISTS: 특정 컬럼값이 존재하는지 여부를 확인한다.
/*EXISTS*/
SELECT *
FROM 고객
WHERE EXISTS(SELECT 1 FROM 주문 WHERE 주문.고객ID = 고객.고객ID)
IN: 괄호 안의 값 혹은 서브쿼리의 결과가 포함되는지 여부를 확인
/*IN*/
SELECT *
FROM 고객
WHERE 고객ID IN(SELECT 고객ID FROM 주문)
/*IN절의 distinct 는 무의미한 명령어이다. 내부적으로 unique 를 하기 때문*/
-- WHERE 고객ID IN(SELECT distinct 고객ID FROM 주문)
(+ )
SELECT절 까지 가 컬럼 값을 직접 비교하는 IN과 다르게 컬럼 값의 존재여부(TRUE/FALSE)만 판단하는 EXISTS가 일반적으로 성능이 좋다. 그러나 대용량 데이터를 조회할 것이 아니라면 성능은 보통 비슷하다...
EXISTS가 데이터의 존재여부만 판단한다면, 두 테이블간의 교집합을 나타내는 INNER JOIN으로도 대체할 수 있을 것 같다. EXISTS와 INNER JOIN 중 어느걸 사용해야 유리할까?
INNER JOIN: JOIN조건에서 동일한 값이 있는 행만 반환
/*INNER JOIN*/
SELECT DISTINCT 고객.* -- 고객테이블의 정보만 필요하므로 중복 제거 필요
FROM 고객 INNER JOIN 주문 ON(고객.고객ID = 주문.고객ID)
INNER JOIN과 EXISTS의 비교를 하려면 INNER JOIN과 EXISTS가 어떻게 동작하는지 더 상세하게 알아봐야 할 것 같다.
다음과 같은 두 테이블이 있다고 가정해보자. 고객테이블에서 한번이라도 주문을 한 고객을 조회해보자.
EXISTS의 경우는 Inner Query를 만족하는 데이터를 처음 만나면 true를 반환하며, 그 이후 중복된 데이터에 대해서는 확인하지 않는다.
/*EXISTS*/
SELECT *
FROM 고객
WHERE EXISTS(SELECT 1 FROM 주문 WHERE 주문.고객ID = 고객.고객ID)
INNER JOIN은 모든 레코드에 JOIN을 하고, 출력결과보다 많은 임시데이터가 생성되며 DISTINCT도 해줘야 하므로 1:N 관계에서 1에 해당하는 테이블을 조회할 때에는 비효율적이다.
/*INNER JOIN*/
SELECT DISTINCT 고객.* -- 고객테이블의 정보만 필요하므로 중복 제거 필요
FROM 고객 INNER JOIN 주문 ON(고객.고객ID = 주문.고객ID)
따라서 보통의 경우에는 INNER JOIN이 유리하겠지만, Inner Query에 중복된 데이터가 많을 경우에서 에는 EXISTS가 유리하다.
참고
https://etloveguitar.tistory.com/124
http://jason-heo.github.io/mysql/2014/05/30/mysql-inner-join-vs-exists.html
https://wakestand.tistory.com/511