기본적으로 표준 SQL(ANSI SQL 표준)이 정의한 실행 순서:
1. FROM
2. WHERE
3. GROUP BY
4. HAVING
5. SELECT
6. ORDER BY
어떤 RDBMS이든 이 기본 흐름을 따른다. 다만, 이는 논리적인 처리 순서일 뿐 RDBMS(Oracle, MySQL, PostgreSQL, SQL Server 등)에서 실제로 이 순서대로 쿼리가 실행되는 것은 아니다. 왜냐하면 쿼리를 더 빠르게 실행하기 위해 여러가지 최적화를 구현하기 때문이다. (이 내용은 아래 3번에서 자세히)

실행 순서와 관련된 SQL 쿼리 특징
(1) SELECT절에 정의한 별칭(alias)을 GROUP BY절에서 바로 사용할 수 없다.
왜냐하면, GROUP BY는 SELECT보다 먼저 실행되기 때문에 아직 SELECT에서 alias가 정의되기 전이라서 인식할 수가 없음. 그래서 GROUP BY에서는 원본 컬럼명이나 식(expression)을 직접 써야 한다.
일부 DBMS는 특수하게 GROUP BY에서도 alias를 허용하는 경우가 있긴 하다. (MySQL이나 SQLite 같은 느슨한 규칙을 가진 DB들에서 허용하기도 하지만 표준 SQL은 아님.) 예외적으로 alias 써도 되는 경우가 있지만 이식성 떨어짐! 다른 DB 옮기면 깨질 수 있기 때문에 코드 이식성(여러 DB에서 다 돌아가게)을 생각하면, 항상 GROUP BY에서는 alias 대신 직접 식을 쓰는 게 안전하다.
[예시]
BAD
SELECT price * quantity AS total_price
FROM sales
GROUP BY total_price; -- 알리아스 그대로 적으면, 에러 발생할 가능성이 높음
GOOD
SELECT price * quantity AS total_price
FROM sales
GROUP BY price * quantity;
(2) Window Function (윈도우 함수)의 결과를 바로 필터링할 수 없다.
윈도우 함수의 결과를 WHERE나 HAVING 같은 구문으로 바로 필터링할 수 없다. 윈도우 함수는 WHERE와 GROUP BY가 실행된 후에 SELECT 구문에서 실행되기 때문이다. 따라서 서브쿼리, CTE(Common Table Expression) 사용하여 필터링해야 한다.
단, BigQuery의 경우 QUALIFY를 사용하여 바로 필터링할 수 있다. QUALIFY 절은 WHERE, GROUP BY, HAVING 중 하나를 같이 사용해야 한다는 것을 알아두자.
-- 방법1: 서브쿼리 (일반적인 RDBMS)
SELECT *
FROM (
SELECT student_id
, year
, class
, score
, RANK() OVER (PARTITION BY class ORDER BY score DESC) as rnk
FROM school
WHERE year = 2020
) AS tmp
WHERE rnk <= 3
-- 방법2: QUALIFY 사용 (BigQuery)
SELECT student_id
, year
, class
, score
, RANK() OVER (PARTITION BY class ORDER BY score DESC) as rnk
FROM school
WHERE year = 2020
QUALIFY rnk <= 3
(3) 실제로는 논리적 순서대로 쿼리가 실행되지 않는다.
1. FROM
2. WHERE
3. GROUP BY
4. HAVING
5. SELECT
6. ORDER BY
어떤 RDBMS이든 이 논리적인 순서 흐름을 기본적으로 따른다. 하지만 실제로 데이터베이스 엔진은 SQL 논리적 처리 순서대로 실행하지 않는다. 왜냐하면 내부적으로 성능을 높이기 위해 여러 가지 최적화(optimization)를 하면서 이로 인해 실행 순서를 바꾸기도 하기 때문이다.
예를 들어
-- JOIN을 나중에 해도 결과가 바뀌지 않으면, 필터를 먼저 해버릴 수 있다. (적은 데이터로 JOIN해서 성능 향상)
-- WHERE 절에서 인덱스를 활용할 수 있으면, 전체 테이블을 다 스캔하지 않는다.
'데이터 처리 도구 > SQL' 카테고리의 다른 글
[SQL] MEDIAN() 없이 중앙값 구하기 (0) | 2025.05.22 |
---|---|
[SQL] COALESCE( ) 는 합치는 함수다. (NULL이 아닌 첫 값으로) (0) | 2025.05.21 |
[SQL] 연산 종류와 우선 순위 (0) | 2025.04.18 |
[MySQL] 집합 연산(2): INTERSECT, EXCEPT (0) | 2024.08.06 |
[MySQL] WITH절 사용하여 CTE 생성하기 (0) | 2024.07.28 |