본문 바로가기
ORACLE/SQL

[Oracle] SQL SELECT 쿼리 실행 순서 처리 과정 :: 마이자몽

by 🌻♚ 2020. 3. 17.

SELECT 쿼리 실행 순서

SQL 쿼리문을 작성할때 사용되는 WHERE, GROUP BY, ORDER BY 절과 같은 구문을 실행하는데 순서가 존재합니다. 이 순서에 의해서 쿼리가 처리되고 어떻게 쿼리문을 작성하느냐에 따라 퍼포먼스의 차이가 발생합니다.

ORACLE HR 계정의 EMPLOYEES 테이블로 어떤 처리 과정에 의해서 SELECT 쿼리가 실행되는지 알아 보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
SELECT
    JOB_ID
    ,AVG(SALARY) SAL_AVG
FROM
    EMPLOYEES
WHERE 
    SALARY > 13000
GROUP BY 
    JOB_ID
HAVING
    COUNT(*> 1
ORDER BY SAL_AVG DESC;

위의 쿼리문을 실행했을 때의 최종 결과입니다. 화면에 출력되는 양은 매우 적지만, 실제 내부적으로 이 결과를 얻기까지 SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY 총 6단계에 걸쳐서 결과를 뿌려줬습니다.

 

 

실행 순서

SELECT 쿼리문을 실행했을때 FROM - WHERE GROUP BY - HAVING - SELECT - ORDER BY 순서대로 실행이 됩니다.

 

 

FROM 절

데이터양이 많이 일부 row만 이미지로 캡쳐

1
FROM EMPLOYEES

SELECT 부터 시작할 것같지만, 쿼리의 가정 첫번째 실행 순서는 FROM절 입니다. FROM 절에서는 전체 테이블의 결과를 갖고 옵니다. INDEX를 사용하지 않는 다는 가정에서 WHERE절이나 SELECT절에서 일부 행이나 열을 제거하여 출력한다고 해도 가장 처음에 테이블의 모든 데이터를 가족 옵니다.

 

 

WHERE 절

1
WHERE SALARY > 13000

WHERE 절에서는 FROM절에서 읽어온 테이블에서 조건에 맞는 결과만 갖도록 데이터를 간추립니다. 

 

 

GROUP BY

1
GROUP BY JOB_ID

GROUP BY 절에서는 WHERE 조건으로 간추린 데이터를 선택한 칼럼으로 GROUPING 작업을 한 결과를 갖고 있습니다. GROUP BY 절을 사용하게 되면 해당 칼럼으로 그룹함수를 사용할 수 있습니다.

 

 

HAVING 절

1
HAVING COUNT(*> 1

HAVING 절은 GROUP BY된 이 후 사용되는 조건 절입니다. 똑같이 조건을 걸 수 있는 WHERE절과는 조금 다르게 써야합니다. WHERE 절에 있는 내용을 HAVING절에서 사용할 수 있습니다. 하지만... HAVING절에서 일반 조건들을 다루게 쿼리 실행 순서에 의해 퍼포먼스가 많이 떨어지게 됩니다.

 

위의 예제에서 "SALARY > 13000"  조건을 WHERE절에서 처리했을 때와 HAVING절에서 처리했을 때를 비교해보겠습니다.

 

HAVING 절 처리

FROM절에서 테이블의 전체 데이터를 불러오고 WHERE절이 아닌 바로 GROUP BY 절로 넘어갑니다. 그렇게 되면 우선 전체 테이블에 대한 GROUPING 작업을 합니다. 그 이후 각각 그룹에 "SALARY > 13000" 조건으로 데이터를 걸러줍니다.

 

WHERE 절 처리

FROM절에서 테이블의 전체 데이터를 불러오고 WHERE절에서 "SALARY > 13000" 조건을 처리하여 데이터의 양을 줄입니다. 그다음 조건에 맞는 데이터만 남은 상태에서 GROUPING 작업을 진행합니다.

 

위의 두가지 처리방법을 봤을때 WHERE 절에서 일발 조건을 처리하는 방식이 효율적이라는 것을 확인 할 수 있습니다. 적은 양의 데이터에서는 큰 차이를 못 느낄 수 있지만, 데이터 양이 늘어날수록 퍼포먼스에 대한 차이가 커질것입니다.

 

 

SELECT 절

1
SELECT JOB_ID, AVG(SALARY) SAL_AVG

여러 조건들을 처리한 후 남은 데이터에서 어떤 열을 출력해줄지 선택하는 절이 SELECT입니다.

 

 

ORDER BY 절

1
ORDER BY SAL_AVG DESC

마지막으로 어떤 열까지 출력할지 정했다면 행의 순서를 어떻게 보여줄지 정렬해주는 절이 ORDER BY 입니다.

 

 

실행순서가 중요한 이유

실행순서에 대한 숙지는 필수입니다. 쿼리를 사용할 때 우리는 최종적으로 출력되는 결과만 육안을 확인할 수 있습니다. 그래서 각 단계에서 어떤 데이터를 읽고 사용할 수 있는지, 실행순서를 모르면 쿼리를 작성하는데 많이 불편할 것 입니다. 실행 순서에 있어서 몇가지 주의해야하는 예시를 확인해 보겠습니다.

 

 

1. ALIAS 사용

1번쿼리 : ORDER BY 절 ALIAS 사용

1
2
3
4
5
6
7
8
SELECT
    EMPLOYEE_ID
    ,FIRST_NAME || ' ' || LAST_NAME AS NAME
    ,SALARY
    ,JOB_ID AS JOB
FROM EMPLOYEES
WHERE SALARY > 5000
ORDER BY NAME;

1번 쿼리에서는 아무 문제가 없습니다. ORDER BY 절은 맨 마지막에 실행되기 때문에 칼럼의 ALIAS를 사용해도 아무 문제가 없습니다.

 

2번쿼리 : WHERE 절 ALIAS 사용

1
2
3
4
5
6
7
8
SELECT
    EMPLOYEE_ID
    ,FIRST_NAME || ' ' || LAST_NAME AS NAME
    ,SALARY
    ,JOB_ID AS JOB
FROM EMPLOYEES
WHERE SAL > 5000
ORDER BY NAME;

그럼 WHERE 절에서 ALIAS를 사용하면 어떨까요? "Invalid Identifier"에러가 발생할겁니다. 이유는 SELECT 절은 WHERE 절 이후에 실행되기 때문에 WHERE 절이 실행 될때는 SAL 칼럼은 아직 존재하지 않는 칼럼입니다.

 

SAL 이라는 칼럼을 WHERE 절에서 사용하기 위해서는 해당 쿼리를 서브쿼리로 사용하여 밖의 SELECT 문장의 WHERE 절에서는 사용이 가능합니다.

 

 

2. ROWNUM 사용

1
2
3
4
5
6
7
8
9
SELECT
    ROWNUM
    ,EMPLOYEE_ID
    ,FIRST_NAME || ' ' || LAST_NAME AS NAME
    ,SALARY
    ,JOB_ID AS JOB
FROM EMPLOYEES
WHERE SALARY > 5000
ORDER BY NAME;

 

ROWNUM을 SELECT에 포함시켜 결과를 출력해봤습니다. 1 부터 출력 될것만 같았던 ROWNUM이 뒤죽박죽 섞여 있습니다. 현재 결과는 NAME 칼럼으로 정렬된 결과 입니다. 'A' 부터 순서대로 NAME칼럼을 기준으로 데이터를 정렬하여 출력된 올바른 출력결과 입니다. 하지만 ROWNUM은 이상하게 섞여 있습니다. 이 문제도 마찬가지로 실행 순서에 따른 결과입니다. 

 

ORDER BY 절은 SELECT 절이 실행된 이후 처리되는 절입니다 . 그래서 ROWNUM은 NAME 칼럼으로 정렬되기 이전의 값에 행을 번호매긴 순서입니다. 우리가 볼 수 있는 출력 결과는 ROWNUM을 매긴 후, NAME 칼럼으로 정렬된 결과 뿐입니다.

 

ROWNUM에 대한 문제는 TOP-N Query나 Row Limiting Clause를 사용하여 해결할 수 있습니다.

TOP-N Query, Row Limiting Clause 참조 링크

 

[Oracle] 오라클 페이징 쿼리 쉽게 만들기 Row Limiting Clause 사용 :: 마이자몽

오라클 페이징 오라클 데이터베이스 페이징 쿼리는 어떻게 작성할까요? 포털 사이트에서 검색을 했을 때, 게시판 형태의 웹사이트에서 결과를 볼때, 한번에 모든 결과를 볼 수 없기 때문에 페이

myjamong.tistory.com

 

태그

댓글3

  • 이재희 2021.06.14 10:45

    질문 있습니다.
    SELECT에서 보고싶은 열을 정하는 건 알겠는데
    AVG(SALARY)는 왜 들어가는 건가요?
    답글

    • Favicon of https://myjamong.tistory.com BlogIcon 🌻♚ 2021.06.14 10:55 신고

      쿼리를 실행해서 결과를 받아오는 순서 중 group by에 대한 내용도 확인하기 위해 집계함수를 사용했습니다.

      단순히 SELECT로 열을 출력하기 위해서는 AVG 함수가 필요 없겠지만... 모든 절의 내용을 포함한 예시를 사용하기 위해 사용했습니다.

  • Favicon of https://soosue.tistory.com BlogIcon soosue 2021.08.21 20:23 신고

    HAVING 절에 관한 내용입니다. 주어진 쿼리(group by job_id)로는 having salary > 13000을 할 수 없다고 생각이 되는데 맞는지 궁금합니다!
    답글