본문 바로가기
자격증 공부/PCSQL

[PCSQL] SELECT 쿼리 작성순서와 실행순서는 다르다.

by ohback1 2025. 10. 8.

SQL을 작성할 때 우리는 SELECT, FROM, WHERE, GROUP BY, ORDER BY 순으로 코드를 작성한다. 하지만 실제로 SQL 쿼리는 우리가 작성한 순서와 다르게 실행되는데, 이 실행 순서를 이해하는 것은 효율적인 쿼리 작성, 디버깅, 성능 최적화에 매우 중요하다.


 

쿼리 작성순서와 실행순서는 어떻게 다를까?

출처: https://ai.atsit.in/posts/5176260605/

우선 우리가 SELECT 구문을 작성할 때는 다음과 같은 순으로 작성한다.

SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT

그러나 실제 내부에서 일어나는 실행 순서는 다음과 같다.

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
  • FROM / JOIN: 데이터를 가져올 테이블을 결정
  • WHERE: 행 단위로 조건을 걸어 데이터를 필터링
  • GROUP BY: 데이터를 그룹화하여 집계할 준비
  • HAVING: 그룹화된 데이터에 조건을 걸어 필터링
  • SELECT: 실제로 출력할 컬럼을 결정
  • DISTINCT: 중복된 행을 제거
  • ORDER BY: 결과를 정렬
  • LIMIT / OFFSET: 출력할 행의 수를 제한

 

실행 순서가 다르다는건 알겠는데, 어떻게 실행되는지까지 알아야 하나요?

출처: https://ai.atsit.in/posts/5176260605/
출처: https://www.inflearn.com/blogs/

 

수학 공식을 이해하고 푸는 것과 외워서 푸는 것이 다르듯 쿼리의 실행순서를 이해하면 좋은 이유는 아주 많다. 대표적 예를 들자면:

 

1. 쿼리 작성의 정확성

WHERE 절은 행 단위로 조건을 적용하는 반면, HAVING 절은 그룹 단위로 조건을 적용한다. 따라서 집계 함수(예: COUNT, SUM)를 WHERE에서 사용하면 오류가 발생할 수 있다.

SELECT department, COUNT(*) AS emp_count  
FROM employees  
WHERE COUNT(*) > 5  
GROUP BY department;

위 쿼리는 오류를 발생시킨다. 이유는 COUNT(*)는 GROUP BY 이후에 계산되므로, WHERE 절에서 사용할 수 없다. 이를 해결하려면 HAVING 절을 사용해야 한다.

SELECT department, COUNT(*) AS emp_count  
FROM employees  
GROUP BY department  
HAVING COUNT(*) > 5;

 

2. 쿼리 성능 최적화

데이터를 조기에 필터링하면 처리해야 할 데이터 양이 줄어들어 성능이 향상한다. 예를 들어, WHERE 절에서 먼저 조건을 걸면 GROUP BY나 SELECT에서 처리할 데이터가 줄어든다.

-- 예: 급여 5000 이상 직원만 그룹화
SELECT department, COUNT(*) AS emp_count
FROM employees
WHERE salary >= 5000 -> 조기 필터링
GROUP BY department;
  • 만약 WHERE를 쓰지 않고 GROUP BY 후 필터링하면, 모든 데이터를 먼저 그룹화 → 메모리 사용량 증가
  • 따라서 WHERE에서 먼저 조건을 거는 것이 효율적

 

3. 복잡한 쿼리 작성 시 오류 방지

SELECT 절에서 정의한 별칭(alias)은 WHERE나 HAVING 절에서 사용할 수 없다. 이는 실행 순서에 따른 제한이다.

SELECT department, COUNT(*) AS emp_count
FROM employees
GROUP BY department
HAVING emp_count > 5;  -- emp_count는 HAVING에서 바로 사용 불가

위처럼 작성하면 HAVING 절에서 오류가 난다. 올바르게 사용하기 위해선 아래와 같이 작성해야 한다.

SELECT department, COUNT(*) AS emp_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;  -- 집계 함수를 직접 사용

추가로 alias를 HAVING에서 쓰고 싶다면 아래와 같이 CTE나 서브쿼리를 사용해야 한다.

WITH dept_count AS (
    SELECT department, COUNT(*) AS emp_count
    FROM employees
    GROUP BY department
)
SELECT department, emp_count
FROM dept_count
WHERE emp_count > 5;

하지만 이 경우, 쿼리 실행이 두 단계로 분리되기 때문에 대규모 연산의 경우 성능(시간복잡도, 메모리 사용량)에 영향이 생길 수 있다.

  • CTE 쿼리 실행
    → employees 전체를 읽고, GROUP BY 수행 후
    → 임시 테이블(dept_count) 형태로 메모리에 저장
  •  외부 SELECT 실행
    → dept_count에서 WHERE emp_count > 5 조건을 적용

이렇듯 데이터의 규모가 클수록 효율적으로 정보를 불러오는 것이 중요하기에, 반드시 실행순서를 이해하고 넘어가야 한다.