SQL IN vs EXISTS
SQL IN vs EXISTS
SQL의 IN / EXISTS
둘 다 특정 조건을 만족하는 데이터를 조회하기 위한 연산자. 하지만 동작 방식에 차이점이 존재.
IN 연산자
- Where 절에서 값이 특정 집합 내에 있는지를 판단하는 연산자.
- 찾고자 하는 열이 집합의 하나 이상의 값과 일치시 True를 반환.
- 집합의 값을 직접 명시하거나 서브쿼리가 올 수 있음.
- 아래의 두 sql은 동일함.
SELECT * FROM users
WHERE id IN (1, 2, 3, 4)
SELECT * FROM users
WHERE id = 1 OR id = 2 OR id = 3 OR id = 4
NOT IN 연산자
- IN의 반대 연산자.
- 값이 특정 집합 내에 없을 경우 True를, 존재하는 경우 False를 반환.
EXISTS 연산자
- Where 절에서 서브쿼리의 값이 존재하는지를 판단하는 연산자.
- EXISTS (서브쿼리) 형태로 구성되며, 서브쿼리의 결과가 존재하면 True, 아닌 경우 False를 반환.
- 테이블간 외래키 관계가 있는 경우 유용.
- 다음 두 sql은 동일함. (아이템을 가진 유저를 찾음)
SELECT * FROM users u
WHERE EXISTS (
SELECT * FROM itmes i
WHERE i.userid = u.id
)
SELECT * FROM users u
WHERE id IN (
SELECT DISTINCT userid FROM items
)
IN vs EXISTS
- IN의 경우 서브 쿼리를 먼저 실행하고 해당 값의 결과를 메인 쿼리의 모든 결과와 비교.
- EXISTS의 경우 메인 쿼리를 먼저 실행해서 얻은 각 값마다 서브쿼리에 대입해서 값이 존재하는지 여부를 판단.
- EXISTS는 존재하는지 여부만 확인하고 SELECT를 수행하지는 않으므로 IN보다 성능이 좋음.
- 둘의 결과는 같으나 NOT IN과 NOT EXISTS는 NULL이 있다면 결과가 다를 수 있음.
NOT IN with NULL
SELECT * FROM users u
WHERE id NOT IN (
SELECT DISTINCT userid FROM items
)
- NOT IN은 값이 서브 쿼리의 결과값들과 모두 다른 경우에만 True를 반환.
- 서브 쿼리의 결과에 NULL이 있는 경우 value != NULL인지를 확인함.
- NULL과의 비교는 False이므로 NOT IN이 성립하지 않게 됨.
- 즉, 서브 쿼리에 NULL이 있는 경우 아무 것도 반환되지 않음.
- 메인 쿼리의 값이 NULL인 경우 이 값은 반환되지 않음.
- 서브 쿼리에 IS NOT NULL을 붙여 NULL을 없애면 올바르게 동작함.
NOT EXISTS with NULL
SELECT * FROM users u
WHERE NOT EXISTS (
SELECT * FROM itmes i
WHERE i.userid = u.id
)
- NOT EXISTS의 경우는 모든 메인 쿼리의 값들에 대해 서브 쿼리에 대입.
- 대입된 서브 쿼리의 결과가 없을 경우에만 True를 반환.
- 메인 쿼리의 값이 NULL인 경우 서브쿼리의 where절이 항상 false가 되어 아무 것도 반환하지 않음.
- 즉, 메인 쿼리의 값이 NULL인 경우 이 값은 반환됨.
NOT IN vs NOT EXISTS
메인 쿼리에 NULL 값이 있는 경우, NOT IN은 이 값을 절대 반환하지 않음. 그러나 NOT EXISTS는 무조건 이 값을 반환함.