최근 작업하고 있는 모듈에서 A 테이블과 B 테이블을 비교하여 B 테이블에 없는 값을 A 테이블에서 가져오는 작업을 진행하고 있다. 처음에는 NOT IN 구문을 사용하여 비교하고 가져오고 있었는데, NOT EXISTS 를 사용하면 더 효과적이라는 말을 듣고, 궁금증에 여기저기 검색해보았다. 결론적으로 말하자면 조회 건수가 많지 않은 쿼리에서는 성능이 비슷하지만, 조회 건수가 급격하게 늘어나면 (NOT)EXISTS 구문이 훨씬 효과적이라는 것이다.
초기 데이터
테이블은 rel1 , rel2 테이블을 생성하였다.
1. (NOT) IN
SELECT * FROM rel1
WHERE number IN (SELECT number FROM rel2);
SELECT * FROM rel1
WHERE number NOT IN (SELECT number FROM rel2);
IN 구문에서는 가장 먼저 서브쿼리(위에서는 rel2) 를 실행하여 number 요소들을 가져온다.
그 다음에는 메인쿼리의 rel1 에서 row를 하나를 가져오고,
서브쿼리의 row들과 메인쿼리의 row 를 비교하여 같은 것만 반환하게 된다.
위의 과정을 메인쿼리의 row 개수만큼 반복하여 비교한다.
IN 구문은 서브쿼리와 메인쿼리의 값 중 하나라도 일치하면 반환해주지만, NOT IN 쿼리는 모든 요소들과 일치하지 않는 값을 체크하여 반환해주게 된다.
여기서 NULL 값은 DB에서 비교연산을 할 때 항상 UNKNOWN(FALSE) 값을 반환하기 때문에 NULL 이 존재하면 아무 결과도 확인할 수 없다. 원하는 값을 보려면 NULL을 제외하고 조회하면 된다.(WHERE number IS NOT NULL)
2. (NOT) EXISTS
SELECT * FROM rel1 t1
WHERE EXISTS (SELECT 1 FROM rel2 t2 WHERE t1.number = t2.number);
SELECT * FROM rel1 t1
WHERE NOT EXISTS (SELECT 1 FROM rel2 t2 WHERE t1.number = t2.number);
EXISTS 구문에서는 IN 구문과 달리 메인쿼리에 먼저 접근하여 row 를 하나 가져오고 EXISTS 의 서브쿼리를 실행시켜
결과가 존재하는지를 판단한다.
서브쿼리의 결과가 TRUE 인지 FALSE 인지 체크하기 떄문에 EXISTS 에서는 TRUE 면
메인쿼리의 결과를 출력하고, NOT EXISTS 에서는 서브쿼리 내 결과가 FALSE 면 메인쿼리의 결과를 출력한다.
여기서 주의할 부분은, 서브쿼리에서 TRUE만 되면 레코드가 출력되기 때문에 두 테이블에서 같은 값을 가져오려면
WHERE 절로 조건을 주어야한다.
NOT EXISTS 에서는 서브쿼리의 결과가 FALSE 면 반환되게 된다.
서브쿼리에서 rel1 과 rel2 의 조인 시 NULL은 위에 IN 에서 설명한 것처럼 비교연산에서 빠지게 되며,
이는 서브쿼리를 FALSE 로 만들고, 반환 조건이 충족되어서 NULL 값이 같이 빠져나오게 된다.
그러므로 IN 에서는 나오지 않은 NULL 값이 NOT EXISTS 에서는 나오는 것을 확인할 수 있다.
3. 정리
- (NOT) IN : 실제 데이터들의 값을 비교하여 일치하는지 확인한다. 특정 값 목록을 기반으로 필터링한다.
- (NOT) EXISTS : 해당 ROW 가 존재하는지만 확인하여, TRUE 혹은 FALSE 를 반환한다. 서브쿼리에서 행의 부재를 기반으로 필터링한다.
- NULL 과의 비교는 항상 UNKNOWN(FALSE) 값을 반환한다.
참조
https://kimeunyeol.tistory.com/m/30
https://doorbw.tistory.com/222
'프로그래밍' 카테고리의 다른 글
[k8s] pod 내부에서 apt update (0) | 2024.01.22 |
---|---|
[geopandas] shp파일을 csv로 변환 및 멀티폴리곤 simplication 작업 (0) | 2023.05.03 |
centos7 에 oracle 19c - silent 버전 설치하기 (2) | 2023.04.07 |
sevice 로그 확인하기 (0) | 2023.04.07 |
시퀀스(sequence) 생성 및 확인, 초기화 방법 (0) | 2023.02.17 |