HomeAbout
SQL
서브쿼리 써, 말아?
이윤희
January 23, 2022
2 min

Table Of Contents

01
서브쿼리의 기본 개념
02
서브쿼리가 일으킬 수 있는 문제들
03
생각해볼 수 있는 해결책 : 연산 비용 줄이기
04
생각해볼 수 있는 해결책 : 가독성 높이기
  • 원 글은 작성자 블로그에서 보실 수 있습니다.

데이터 추출을 위해 SQL 구문을 작성하다보면, 잦은 빈도로 서브쿼리를 사용하게 됩니다. “서브쿼리는 실행 속도가 느리다던데..” 막연하게 알고 계신가요? 네, 저도 그랬어요 😇 그래서 공부하고 정리해 보았습니다. 서브쿼리가 전체 성능에 어떤 영향을 미치는지, 어떤 대안을 활용할 수 있는지 함께 알아보아요.

서브쿼리의 기본 개념

서브쿼리는 괄호 안에 완전한 SELECT 문을 넣어 생성한 테이블 표현식이에요. 쉽게 말하면 쿼리 안에 또 다른 쿼리가 들어 있는 것이지요. 통상 FROM 혹은 JOIN 구문에 서브쿼리를 사용하는 경우가 많을 텐데요. 이 외에도 서브쿼리의 쓰임새는 광범위 합니다. 아래서 몇 가지 활용 예시를 소개 합니다.

테이블 서브쿼리

  • 테이블이나 뷰의 이름, 테이블을 반환하는 저장 프로시저나 함수 이름을 사용할 수 있는 곳에 활용
  • 우리가 흔히 사용하는 여러 데이터 집합을 결합(Join)할 때 FROM 절에 사용되는 서브쿼리가 이 유형에 해당합니다. 이 외에도 자주 사용하지는 않지만, EXIST 조건에 서브쿼리를 사용하는 예시를 한 가지 소개할게요.

테이블 서브쿼리 예시
테이블 서브쿼리 예시

단일 컬럼 테이블 서브쿼리

  • 테이블 서브쿼리나 값의 목록을 IN 조건으로 비교 하는 곳에 활용
  • WHERE 절에서 IN (혹은 NOT IN) 구문을 활용한 서브쿼리를 사용하는 경우는 많은 분들께 익숙한 방식일 거에요. 그런데 아래처럼 CASE 문에서도 유사하게 IN 구문을 활용할 수 있다는 사실을 아시나요?

단일 컬럼 테이블 서브쿼리 예시
단일 컬럼 테이블 서브쿼리 예시

스칼라 서브쿼리

  • 컬럼 이름이나 컬럼 이름에 대한 표현식을 다른 용도로 사용하는 곳에 활용 (단일 로우에 있는 한 컬럼에 값을 0개 또는 1개만 반환)
  • 설명만 보면 이게 무슨 의미인가- 싶지만, 예시를 보면 금방 이해될 거에요!

스칼라 서브쿼리 예시
스칼라 서브쿼리 예시

서브쿼리가 일으킬 수 있는 문제들

이토록 유연하고 다양한 기능을 제공하는 서브쿼리, 왜 문제가 되는 걸까요? 가장 큰 문제는 성능 저하입니다. 서브쿼리는 테이블과 같은 형태의 결과 값을 만들어 내지만, 실제 데이터를 저장하지는 않기 때문에 성능 저하를 야기할 수 있어요.

연산 비용 추가

  • 위에서 말한 것처럼 서브쿼리는 실체적인 데이터를 저장하지 않기 때문에, 서브쿼리에 접근할 때마다 SELECT 구문을 실행해서 데이터를 만들어 내게 됩니다.
  • 서브쿼리의 내용이 복잡할 수록 실행 비용이 올라감은 물론이고요!

데이터 I/O 비용 발생

  • 연산 결과는 어딘가에 저장하기 위해서 써(Input) 두어야 합니다. 연산 결과의 크기에 따라 데이터 저장 비용이 달라지고, 저장소 성능에 따라서는 접근 속도가 급격하게 떨어질 수 있어요.

최적화를 받을 수 없음

  • 서브쿼리로 만들어지는 데이터는 테이블과 다르게 데이터를 설명하는 메타 정보를 가지고 있지 않아요. 그렇게 때문에 옵티마이저(SQL 실행 계획을 수립, 관리하는 시스템)가 쿼리를 해석하기 위해 필요한 정보를 서브쿼리에서 읽어낼 수 없습니다.

서브쿼리의 또 다른 단점은 가독성입니다. 코드가 여러 계층에 걸쳐 만들어 지면서 가독성이 떨어지고, 가독성이 낮은 쿼리는 유지, 관리가 어렵습니다. 비단 SQL 쿼리, 그리고 서브쿼리에 국한된 내용은 아니지만 가독성 좋은 코드에 대한 몇 가지 좋은 글을 함께 공유 합니다.

생각해볼 수 있는 해결책 : 연산 비용 줄이기

특정 테이블에 대한 접근 횟수가 많을 수록, 데이터를 읽고 쓰는 비용이 늘어나요! 그러니 쿼리를 (더 좋은 방향으로) 수정할 때는 여러 번 호출된 테이블의 접근 횟수를 줄일 수 있는지 생각해 보아요. 아래 WINDOW 함수 활용 예시를 보면, Receipts 테이블에 대한 접근 횟수를 2회에서 1회로 줄인 것을 알 수 있어요.

연산 비용 줄이기리 예시
연산 비용 줄이기리 예시

생각해볼 수 있는 해결책 : 가독성 높이기

들여쓰기의 늪
들여쓰기의 늪

무분별한 서브쿼리 사용의 또 다른 폐해는 가독성이 떨어진다는 점이었죠. 이 점을 보완하기 위해서는 CTE(Common Table Expression)을 활용하면 좋습니다. 유사한 패턴의 서브쿼리를 여러 번 반복적으로 사용하는 경우, WITH 구문 사용 여부의 차이가 더 두드러지게 나타나요.

CTE 예시
CTE 예시

CTE를 통해 만들어지는 결과 값 또한 임시 테이블의 일종이기 때문에, 쿼리 성능을 고려해서 꼭 필요한 데이터만 필터할 것을 권장합니다. CTE 구문의 모든 컬럼은 다른 쿼리에서 사용되지 않는 경우에도 연산되니 주의하세요!


위에서 소개한 여러 해결책을 코드를 작성하는 첫 단계부터 적용하기란 쉽지 않습니다. 외려, 처음 쿼리를 고민할 때는 먼저 서브쿼리를 사용하면서 연산의 논리를 전개하는 게 일의 속도와 효율에 도움이 될 수 있어요. 그러니 처음부터 기능과 성능이 모두 우수한 쿼리를 작성하려고 끙끙대기 보다, 빠르게 만들들고 성능을 고려해서 튜닝 하기를 권장합니다. 반복적으로 활용되는 쿼리라면 더더욱이요!

Reference

  • 존 비아시에스, 더글러스 스틸, 벤 클로디어, <SQL 코딩의 기술>, 길벗(2017)
  • 미크, <SQL 레벨업>, 한빛미디어(2016)

Tags

#데이터분석#SQL

Share


Related Posts

SQL을 작성할 때 놓치기 쉬운 5가지
2022-01-31
4 min
© 2023, All Rights Reserved.
Powered By

Quick Links

About UsOfficial Page

Social Media