본문으로 바로가기

SQL 논리 실행 순서 — 적힌 순서대로 돌지 않는다

SELECT가 맨 앞에 적혀 있어도 실행은 FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT 순 — 행 집합이 단계마다 걸러지는 것을 실행한다.

1 / 7질의는 적힌 순서가 아니라 실행 순서로 움직입니다: FROM → WHERE → GROUP BY → HAVING → SELECT/ORDER BY → LIMIT. 행이 어떻게 걸러지는지 봅니다.
FROMWHEREGROUP BYHAVINGSELECT/ORDERLIMIT
서울80부산30서울60대구90부산70대구40
단계 목록 · 키보드 ←/→ 이동, Space 재생

SQL은 적힌 순서(SELECT부터)가 아니라 논리 순서(FROM부터)로 돈다 — WHERE와 HAVING의 차이, SELECT 별칭을 WHERE에서 못 쓰는 이유가 전부 이 순서 하나에서 나온다.

왜 헷갈리는가

"WHERE total > 100이 왜 에러지? total은 위에 SELECT에서 만들었는데" — SELECT는 WHERE보다 뒤에 실행되므로 그 시점에 별칭이 아직 없다. "집계 조건은 왜 HAVING에?" — WHERE 시점엔 그룹이 아직 없어서 집계값 자체가 존재하지 않는다.

순서가 풀어 주는 수수께끼들

논리 순서 FROM→(JOIN·ON)→WHERE→GROUP BY→HAVING→SELECT→DISTINCT→ORDER BY→LIMIT를 대면 흔한 에러가 전부 설명된다.

  • WHERE에서 SELECT 별칭 사용 불가 — 별칭은 SELECT 단계에서 태어난다. (ORDER BY에서는 가능 — SELECT보다 뒤라서.)
  • 집계 함수는 WHERE에 못 쓴다 — 그룹이 GROUP BY에서야 생기므로, 그룹 조건은 HAVING으로.
  • WHERE로 먼저 줄이고 HAVING은 최소로 — 행 필터가 이르면 이를수록 싸다(옵티마이저가 대개 알아서 하지만, 논리적으로 옳은 자리에 쓰는 습관이 안전하다).
  • LIMIT은 맨 끝 — '정렬 후 상위 10'이지 '10개 뽑아 정렬'이 아니다.
  • LEFT JOIN의 함정: 오른쪽 테이블 조건을 WHERE에 쓰면 NULL 행이 걸러져 INNER JOIN이 돼 버린다 — 그 조건은 ON으로. (ON은 조인 시점, WHERE는 조인 후.)

논리 순서 vs 물리 실행

이 순서는 '의미'의 순서다. 옵티마이저는 결과가 같다면 물리적으로는 순서를 바꾼다(조건 푸시다운, 인덱스로 정렬 생략 등). 그래서 성능 논의는 EXPLAIN이 진실이고, 논리 순서는 '무엇이 가능하고 무엇이 에러인가'의 진실이다 — 두 층을 구분하면 SQL 논쟁의 절반이 정리된다.

기억할 것

  • 실행은 FROM부터, SELECT는 거의 끝 — 적힌 순서에 속지 말 것.
  • WHERE=행 필터(그룹 전), HAVING=그룹 필터(집계 후).
  • 별칭은 SELECT에서 태어난다 — WHERE 불가, ORDER BY 가능.
  • LEFT JOIN의 오른쪽 조건은 ON에 — WHERE에 쓰면 INNER가 된다.
  • 의미는 논리 순서가, 성능은 EXPLAIN이 진실이다.
SQL 논리 실행 순서 — 적힌 순서대로 돌지 않는다 | KIE