최근 프로그래머스의 없어진 SQL 문제(없어진 기록 찾기)를 풀었는데 두 가지 풀이법[1]이 있음을 알았습니다. 평소 떠오르는대로 SQL을 짜는 편인데 이 기회를 통해 두 방법의 차이에 대해 공부, 기록하면 좋겠다 싶어 작성합니다(특히 다음 글을 많이 참고하였습니다). 글의 내용은 공부하며 보완해나갈 예정입니다.
_____
조인과 서브쿼리는 때로 동일한 결과를 얻을 수 있다. 따라서 쿼리 작성 시 서브쿼리를 사용할지 조인을 사용할지 선택하는 것이 필요하다. 이 두 녀석은 차이가 있고(아직은 잘 모르), 많은 경우 서브쿼리가 사용하기 쉬워보이지만 효율성의 측면에서 조인이 권장된다[2]. 그렇다면 어떤 경우 서브쿼리를 조인으로 대체해야 할까?[4]
첫째, 스칼라 서브쿼리[5]다. 아래 예를 보자.
// 방법1. 서브쿼리
SELECT name
, cost
FROM product
WHERE id = (SELECT product_id
FROM sale
WHERE price = 2000
AND product_id = product.id);
// 방법2. 조인
SELECT p.name
, p.cost
FROM product p
JOIN sale s
ON p.id = s.product_id
WHERE s.price = 2000;
둘째, IN절 안에 있는 서브쿼리(혹은 NOT IN절 안에 서브쿼리)다.
// IN절 안 서브쿼리
// 방법1. 서브쿼리
SELECT name
, cost
FROM product
WHERE id IN (SELECT product_id
FROM sale);
// 방법2. 조인
SELECT DISTINCT p.name
, p.cost
FROM product p
JOIN sale s
ON s.product_id = p.id; // [6]
// NOT IN절 안 서브쿼리
// 방법1. 서브쿼리
SELECT name
, cost
FROM product
WHERE id NOT IN (SELECT product_id
FROM sale);
// 방법2. 조인
SELECT DISTINCT p.name
, p.cost
FROM product p
LEFT JOIN sale s
ON s.product_id = p.id
WHERE s.product_id IS NULL;
셋째,
_____
1. 각 풀이는 다음과 같다. 둘 중 어떤 풀이가 선호될까?
-- 풀이1. 서브쿼리
SELECT a.ANIMAL_ID
, a.NAME
FROM ANIMAL_OUTS a
WHERE a.ANIMAL_ID NOT IN (SELECT b.ANIMAL_ID
FROM ANIMAL_INS b)
ORDER BY a.ANIMAL_ID
, a.NAME;
-- 풀이2. 조인
SELECT OUTS.ANIMAL_ID
, OUTS.NAME
FROM ANIMAL_OUTS AS OUTS
LEFT OUTER JOIN ANIMAL_INS AS INS
ON INS.ANIMAL_ID = OUTS.ANIMAL_ID
AND INS.ANIMAL_TYPE = OUTS.ANIMAL_TYPE
WHERE INS.INTAKE_CONDITION IS NULL
ORDER BY OUTS.ANIMAL_ID;
2. 조인으로 대체할 수 있는 서브쿼리는 대부분 조인으로 작성할 것을 권한다고 한다. 본문에도 적었지만, WHERE 절에 사용되는 IN 서브쿼리(혹은 NOT IN 서브쿼리)는 조인으로 작성할 것을 권장한다고 한다. 단, EXISTS 서브쿼리의 경우[3]는 유용하게 쓰인다고 한다.
3.
4. 이하의 SQL은 아래 테이블을 기준으로 합니다.
5. 스칼라 서브쿼리의 장단점은 아래와 같다.
- 단점: 메인쿼리 결과 건수만큼 반복 수행된다.
- 장점:
따라서
6.
_____
참고자료
- Subquery vs. JOIN
- Gurubee] 조인과 서브쿼리의 차이점
- OKKY] 조인과 서브쿼리, 사용 시점
- OKKY] 조인과 서브쿼리, 성능 비교
- Gurubee] 스칼라 서브쿼리
'공부 > Database' 카테고리의 다른 글
조회 성능 (0) | 2024.11.05 |
---|---|
Database 경험 (0) | 2024.11.05 |
LISTAGG Function (0) | 2021.01.12 |
서브쿼리 사용 예시 (0) | 2020.12.12 |
댓글