본문 바로가기
프로젝트(종료)/SQLD 자격증 따기

[SQL] 서브쿼리는 언제 쓰는걸까?

by 일말고프로젝트 2021. 4. 7.

 

처음 서브쿼리가 들어간 쿼리를 봤을 때 "왜 이렇게 잘난척 하면서 쿼리를 짠거지?"라고 생각했다. 당시 SQL 문법을 갓 떼고 나름 SELECT FROM WHERE 등을 조합해 쿼리를 짤 줄만 알던 시기였다. 서브쿼리가 뭔지는 알았고, 어떻게 짜는지는 알고는 있었지만, 언제, 왜 짜는지는 몰랐기 때문에 괜히 잘난척 하는 것처럼 보였던 것 같다....

 

SQL 서브쿼리 정의

하나의 SQL 문 안에 또다른 SQL 문이 포함되어 있는 경우

 

서브쿼리 사용 가능한 곳

1. SELECT 절

스칼라 서브쿼리라고도 하며 한 행, 한 컬럼만을 반환하는 서브쿼리를 말함

SELECT T1.C1 
     ,(SELECT AVG(T2.C1)
         FROM TEMP2 T2)
FROM TEMP1 T1;

 

2. FROM 절

인라인 뷰 라고 하며 동적으로 생성된 테이블인 것처럼 사용할 수 있음.

본 SQL 문이 실행될 때만 임시적으로 생성되는 동적인 뷰이기 때문에 데이터베이스에 해당 정보가 저장되지 않음.

 

뷰 생성의 장점

장점

 설명

 독립성

 테이블 구조가 변경되어도 뷰를 사용하는 응용 프로그램은 변경하지 않아도 된다.

 편리성

 복잡한 질의를 뷰로 생성함으로써 관련 질의를 단순하게 작성할 수 있다.

 보안성

 숨기고 싶은 정보가 존재하는 경우, 뷰를 생성할 때 해당 컬럼을 빼고 생성하여 정보를 숨길 수 있다.

 

SELECT T1.C1,T2.C1,T2.C2
FROM TEMP1 T1
    ,(SELECT C1, C2 FROM TEMP2) T2
WHERE T1.C1 = T2.C1;

 

3. WHERE 절

단일 행 서브 쿼리

서브쿼리가 단일 행 비교 연산자(=, <, <=, >, >=, <>)와 함께 사용할 때는 서브쿼리의 결과 건수가 반드시 1건 이하여야 함

 

SELECT C1,C2,C3
FROM TEMP1
WHERE C1 <= (SELECT AVG(C1) FROM TEMP2 WHERE C2 = '3')
ORDER BY C1, C2, C3;

 

다중 행 서브쿼리

서브쿼리의 결과가 2건 이상 반환될 경우 다중 행 비교 연산자(IN, ALL, ANY, SOME)와 함께 사용해야 함.

 

 다중 행 연산자

 설명

 IN

 서브쿼리의 결과에 존재하는 임의의 값과 동일한 조건을 의미한다.

 ALL

 서브쿼리의 결과에 존재하는 모든 값을 만족하는 조건을 의미한다.

 ANY

 서브쿼리의 결과에 존재하는 어느 하나의 값이라도 만족하는 조건을 의미한다.

 EXISTS

 서브쿼리의 결과를 만족하는 값이 존재하는지 여부를 확인하는 조건을 의미한다.

 

SELECT C1, C2, C3
FROM TEMP1
WHERE C1 IN (SELECT C1 FROM TEMP2 WHERE C2 = '3')
ORDER BY C1, C2, C3;

 

다중 칼럼 서브쿼리

서브쿼리 결과로 여러 개의 컬럼이 반환되어 메인쿼리의 조건과 동시에 비교되는 것을 의미함

 

SELECT C1, C2, C3
FROM TEMP1
WHERE (C1, C2) IN (SELECT C1, C2 FROM TEMP2 WHERE C2 = '3')
ORDER BY C1, C2, C3;

 

연관 서브쿼리

서브쿼리 내에 메인쿼리 컬럼이 사용된 서브쿼리

SELECT T1.C1, T1.C2, T1.C3
FROM TEMP1 T1
WHERE (T1.C1, T1.C2) IN (SELECT T2.C1, T2.C2 FROM TEMP2 T2 WHERE T2.C2 = T1.C2)
ORDER BY T1.C1, T1.C2, T1.C3;

 

4. HAVING 절

그룹함수와 함께 사용될 때 그룹핑된 결과에 대해 부가적인 조건을 주기 위해 사용

SELECT T1.C1, T2.C1, T2.C2
FROM TEMP1 T1, TEMP2 T2
WHERE T1.C1 = T2.C1
GROUP BY T1.C1, T2.C1, T2.C2
HAVING AVG(T1.C1) < (SELECT AVG(C1) FROM T2 );

 

5. ORDER BY 절

SELECT *
FROM TEMP1 T1
ORDER BY C1;
 
SELECT *
FROM TEMP2 T2  
ORDER BY (SELECT C1 FROM T1 WHERE T1.C2 = T2.C2);

 

6. INSERT 문의 VALUES 절

INSERT INTO TEMP1 (C1, C2, C3)
VALUES ((SELECT C1 FROM TEMP2), (SELECT C2 FROM TEMP2), (SELECT C3 FROM TEMP2));

 

7. UPDATE 문의 SET 절

UPDATE TEMP1 T1
SET T1.C1 = (SELECT T2.C1 FROM TEMP2 T2 WHERE T2.C1 = T1.C1);

 

 

서브쿼리를 쓰면 좋을 때

좋은 정리 글이 있어 참고!

- 테이블 : 영속적인 데이터를 저장
- 뷰 : 영속적이지만 데이터는 저장하지 않음. 따라서 접근할 때마다 SELECT문이 실행됨
- 서브쿼리 : 비영속적인 생존기간(스코프)이 SQL구문 실행 중으로 한정됨

서브 쿼리는 기능적으로 유연하기 때문에 빈번하게 사용되지만 비기능적인 관점에서보면 테이블에 비해 성능이 떨어지는 경향이 있다. 서브 쿼리의 성능적 문제는 서브 쿼리가 데이터의 실체를 저장하지 않고 있다는 점에 기인하며, 다음과 같다.

 - 연산 비용: 매번 SELECT 문이 실행되기 때문(내용이 복잡할수록 비용이 크다)
 - 데이터 I/O 비용: 서브 쿼리의 결과 데이터 양이 크면 연산 결과를 저장소에 쓰기 때문 
 - 최적화 불가능: 서브 쿼리의 결과 집합에는 인덱스나 제약조건이 없기 때문

이러한 문제점 때문에 내부적으로 복잡한 연산을 수행하거나 결과 크기가 큰 서브 쿼리를 사용할 때는 성능 리스크를 고려해야 한다. 서브 쿼리는 유연성으로 인해 코딩을 할때는 편리하나, 해당 내용이 서브 쿼리를 꼭 사용해야 하는지를 항상 고민해야 한다.

...

그렇다면 서브 쿼리를 사용하는 것이 더 나은 상황은 언제일까? (중략)

테이블을 조인할 때는 조인 대상 레코드 수를 최대한 줄이는 것이 중요한데, 가끔 옵티마이저가 제대로 판단하지 못할 때는 사용자가 직접 연산 순서를 명시해줌으로써 성능적으로 좋은 결과를 얻을 수 있다. 

[출처] 서브 쿼리와 성능|작성자 Joel

 

코딩강아지 : 네이버 블로그

하룻강아지 프로그래머 https://github.com/kovermino

blog.naver.com

 

사실 정리하신 글에서는 실행계획과 예제를 통해 굉장히 깊게 설명해주셨지만, 아직 내 레벨에서는 다루기 어려우니 시간을 두고 이해해봐야겠다..

 

 

댓글