본문 바로가기
일일퀘스트 일일퀘스트

SQLD 단일 행 다중 행 서브쿼리 차이와 연산자(IN, EXISTS) 활용법

ace 읽는 시간 약 2분

데이터베이스 쿼리의 핵심 서브쿼리 이해하기

데이터베이스를 다루다 보면 가장 자주 마주치는 개념 중 하나가 바로 서브쿼리입니다. 서브쿼리는 쉽게 말해 ‘질의문 안의 질의문’을 의미합니다. 복잡한 데이터를 추출할 때 한 번의 쿼리로 해결하기 어려운 경우, 괄호를 사용하여 메인 쿼리 안에 작은 쿼리를 하나 더 넣는 방식입니다. 하지만 많은 초보 개발자와 데이터 분석가들이 서브쿼리를 사용할 때 ‘단일 행’과 ‘다중 행’이라는 개념에서 혼란을 겪곤 합니다. 이 두 가지를 명확히 구분하지 않으면 쿼리가 실행되지 않거나, 의도치 않은 결과를 얻게 됩니다.

단일 행 서브쿼리와 다중 행 서브쿼리의 정의

먼저 서브쿼리의 결과가 몇 개의 행(Row)을 반환하느냐에 따라 분류가 달라집니다.

단일 행 서브쿼리

단일 행 서브쿼리는 결과값이 오직 하나만 반환되는 쿼리입니다. 예를 들어 ‘특정 직원의 평균 급여보다 많은 급여를 받는 사원 조회’와 같은 경우, 평균 급여는 단 하나의 숫자 값으로 나오기 때문에 단일 행 서브쿼리에 해당합니다. 이 경우 메인 쿼리와 서브쿼리를 연결할 때 일반적인 비교 연산자(=, >, <, <>, <=, >=)를 자유롭게 사용할 수 있습니다.

다중 행 서브쿼리

반면 다중 행 서브쿼리는 결과값이 여러 개 반환되는 쿼리입니다. ‘각 부서별 최고 급여를 받는 사원들’을 조회하는 경우, 부서가 여러 개라면 최고 급여 결과값도 여러 개가 나오게 됩니다. 이때는 일반 비교 연산자를 사용하면 데이터베이스 시스템이 “결과가 여러 개인데 어떤 값과 비교해야 할지 모르겠다”라는 오류를 발생시킵니다. 따라서 다중 행 서브쿼리 전용 연산자인 IN, ANY, ALL, EXISTS 등을 사용해야 합니다.

비교 연산자 사용 시 흔히 발생하는 오해와 진실

많은 입문자가 가장 많이 하는 실수는 다중 행 서브쿼리의 결과가 여러 개임에도 불구하고 등호(=)를 사용하는 것입니다. 예를 들어, 특정 부서에 속한 사원들의 명단을 가져오고 싶을 때, 서브쿼리 결과가 여러 명임에도 불구하고 WHERE ID = (SELECT ID FROM …)와 같이 작성하면 시스템 오류가 발생합니다. 이는 수학적으로 1=3, 1=5, 1=9와 같이 여러 값이 하나의 변수와 동시에 같을 수 없기 때문입니다.

  • 오해: 서브쿼리는 무조건 하나의 결과만 나와야 한다.
  • 사실: 서브쿼리는 결과의 개수에 따라 사용하는 연산자가 달라질 뿐, 여러 행을 반환하는 것 자체가 잘못된 것은 아니다.
  • 오해: 단일 행 연산자만 알면 모든 쿼리를 짤 수 있다.
  • 사실: 실무 데이터는 항상 여러 행을 반환하므로 다중 행 연산자 숙달이 필수적이다.

다중 행 서브쿼리 연산자의 실무 활용법

다중 행 서브쿼리를 다룰 때 반드시 알아야 할 핵심 연산자들은 다음과 같습니다.

IN 연산자

가장 많이 쓰이는 연산자로, 서브쿼리의 결과 목록 중 하나라도 일치하면 참(True)을 반환합니다. ‘부서 코드가 10번 또는 20번인 사원’을 찾을 때 매우 유용합니다.

ANY와 SOME 연산자

ANY는 서브쿼리의 결과 중 하나라도 조건을 만족하면 참이 됩니다. 예를 들어 ‘> ANY’는 ‘결과값 중 가장 작은 값보다 크면’이라는 의미가 되어, 결과적으로 최소값보다 큰 모든 데이터를 가져오게 됩니다.

ALL 연산자

ALL은 서브쿼리의 모든 결과값을 만족해야 합니다. ‘> ALL’은 ‘결과값 중 가장 큰 값보다 크면’이라는 의미가 되어, 전체 범위에서 가장 큰 값보다 큰 데이터를 찾을 때 사용합니다.

EXISTS 연산자

EXISTS는 결과값이 존재하는지 여부만 확인합니다. 데이터의 실제 값은 중요하지 않고, ‘데이터가 있느냐 없느냐’가 중요할 때 성능 면에서 매우 효율적입니다. 대규모 데이터베이스에서 쿼리 최적화가 필요할 때 자주 사용됩니다.

효율적인 쿼리 작성을 위한 전문가의 조언

데이터베이스 성능을 고려한다면 서브쿼리 사용을 무조건 피하기보다는 상황에 맞게 최적화하는 전략이 필요합니다. 전문가들은 다음과 같은 조언을 건넵니다.

첫째, 가급적이면 서브쿼리보다는 JOIN을 사용하여 데이터를 추출하는 것이 좋습니다. 물론 서브쿼리가 가독성은 좋을 수 있지만, 대규모 데이터셋에서는 JOIN이 실행 계획상 더 효율적인 경우가 많습니다. 서브쿼리를 사용해야만 하는 상황이라면, 서브쿼리의 결과가 너무 커지지 않도록 필터링 조건을 잘 설정해야 합니다.

둘째, EXISTS와 IN을 적절히 구분하세요. 데이터의 존재 여부만 확인한다면 IN보다는 EXISTS가 더 빠를 가능성이 높습니다. 반대로 특정 값들과의 비교가 필요하다면 IN을 사용하는 것이 논리적으로 명확합니다.

셋째, 서브쿼리의 중첩을 피하세요. 서브쿼리 안에 또 서브쿼리가 들어가는 구조는 쿼리의 복잡도를 급격히 높이고 유지보수를 어렵게 만듭니다. 이런 경우에는 임시 테이블을 만들거나 WITH 절(Common Table Expression)을 사용하여 쿼리를 단계별로 분리하는 것이 훨씬 생산적입니다.

자주 묻는 질문과 답변

Q1. 쿼리를 실행했는데 ‘Single-row subquery returns more than one row’라는 에러가 떠요. 어떻게 해결하나요?

A. 이 에러는 서브쿼리 결과가 여러 행인데 등호(=) 연산자를 사용했을 때 발생하는 전형적인 오류입니다. 서브쿼리의 결과를 확인해 보고, 여러 행이 나온다면 등호를 IN 연산자로 변경해 보세요.

Q2. 서브쿼리를 사용하는 것과 조인을 사용하는 것 중 무엇이 더 좋은가요?

A. 무조건적인 정답은 없습니다. 읽기 쉬운 코드를 원한다면 서브쿼리를, 대규모 데이터 처리에서 성능이 중요하다면 조인을 권장합니다. 하지만 최신 데이터베이스 엔진은 서브쿼리를 내부적으로 조인처럼 처리하기도 하므로, 실행 계획(Explain Plan)을 확인하는 습관을 들이는 것이 좋습니다.

Q3. 다중 행 서브쿼리에서 ALL 연산자를 쓰면 어떤 결과가 나오나요?

A. ALL 연산자는 모든 조건을 만족해야 하므로 가장 엄격한 조건입니다. 예를 들어 ‘> ALL(10, 20, 30)’은 30보다 큰 값만 가져오게 됩니다. 이는 결과적으로 MAX(값)보다 큰 것을 찾는 것과 동일한 논리입니다.

비용 효율적인 데이터베이스 운영을 위한 팁

데이터베이스 서버의 자원은 한정적입니다. 잘못 작성된 서브쿼리는 전체 시스템의 속도를 저하시키고, 클라우드 환경에서는 비용 증가의 원인이 되기도 합니다. 비용 효율적인 운영을 위해 다음의 습관을 가져보세요.

    • 불필요한 서브쿼리 제거: 메인 쿼리에서 이미 걸러진 데이터에 대해 다시 서브쿼리를 돌리고 있지는 않은지 검토하세요.
    • 인덱스 활용: 서브쿼리 내부에 사용되는 컬럼에 인덱스가 걸려 있는지 확인하세요. 인덱스가 없는 컬럼을 기준으로 서브쿼리를 돌리면 데이터베이스는 전체 테이블을 뒤져야 하므로 매우 느려집니다.
    • 결과 집합 최소화: 서브쿼리 내부에서 필요한 컬럼만 선택(SELECT)하고, 불필요한 전체 행을 다 가져오지 않도록 WHERE 절을 정교하게 다듬으세요.
    • 실행 계획 확인: ‘EXPLAIN’ 명령어를 사용하여 쿼리가 어떻게 작동하는지 시각화해 보세요. 서브쿼리가 몇 번 반복 실행되는지 파악하는 것만으로도 성능 개선의 실마리를 찾을 수 있습니다.

데이터베이스 쿼리는 단순히 결과값을 가져오는 도구를 넘어, 데이터를 어떻게 효율적으로 구조화하고 다룰 것인가에 대한 논리적 사고의 과정입니다. 단일 행과 다중 행 서브쿼리의 차이를 이해하는 것은 이 과정의 첫걸음입니다. 지금 작성하고 있는 쿼리가 어떤 형태의 결과를 반환하는지, 그리고 그에 맞는 적절한 연산자를 사용하고 있는지 점검해 보세요. 작은 차이가 모여 시스템의 안정성과 속도를 결정짓는 큰 차이를 만들어낼 것입니다.

ace

ace
함께 보면 좋은 글

댓글 0

첫 댓글을 남겨보세요.

error: Content is protected !!

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.