Database

SELECT 문장 실행 순서와 Order by, ROWNUM조건

천방지축 개발노트 2020. 9. 12. 18:41

 

SELECT 문장 실행 순서

GROUP BY절과 ORDER BY가 같이 사용될 때, SELECT문은 6개의 절로 구성이 되고, 수행 단계는 아래와 같다.

(추가적으로 "계층형 질의문 실행 순서"는 여기를 클릭하여 확인하시면 됩니다.)

실행 순서 Query 문장 상세 내용
5 select [Alias명] ①데이터 값을 출력/계산함.(select)


②from절에 테이블에 대한 Alias를 정의했다면, select절이나 where절에 일반 테이블명을 사용하면 파싱에러 발생. 정의한 Alias를 사용해야 한다.
1 from 테이블명 발췌 대상 테이블을 참조 (from)
2 where 조건식 발췌 대상이 아닌 것들 제거(필터링) (where)
3 group by 칼럼이나 표현식 행들을 소그룹화 함. (group by)
4 having 그룹조건식 그룹핑된 값을 조건에 맞는 것만을 출력(having)
6 order by 칼럼이나 표현식 ①데이터를 정렬함(order by) ※Default값은 ASC(오름차순)
이처럼 Oracle의 경우, 정렬이 완료된 후 데이터의 일부가 출력되는 것이 아니라, 데이터의 일부가 먼저 추출(select)된 후 데이터의 정렬작업이 일어남. 다시 말해, ORDER BY 절은 결과 집합을 결정하는데 관여하지 않음.

예) 해당 쿼리는 아래에서 자세히 설명.
select A, B From emp Where ROWNUM < 4 Order by B DESC;

 

위 순서는 Optimizer 가 SQL문장의 syntax, semantic에러를 점검하는 순서이기도 하다. 예를 들어, from절에 정의되지 않은 테이블의 칼럼을 where절, group by절, having, select, order by절에 사용하면 에러 발생한다.

 

또한 관계형 데이터베이스는 데이터를 메모리에 올릴 때 행 단위로 모든 칼럼을 가져오게 되므로, SELECT 절에서 일부 칼럼만 선택하더라도 ORDER BY 절에서 메모리에 올라와 있는 다른 칼럼의 데이터를 사용할 수 있다.

 

그러나 서브쿼리의 SELECT 절에서 선택되지 않은 칼럼들은 계속 유지되는 것이 아니라 서브쿼리 범위를 벗어나면 더 이상 사용할 수 없게 된다. (인라인 뷰도 동일함) GROUP BY 절에서 그룹핑 기준을 정의하게 되면 데이터베이스는 일반적인 SELECT 문장처럼 FROM 절에 정의된 테이블의 구조를 그대로 가지고 가는 것이 아니라, GROUP BY 절의 그룹핑 기준에 사용된 칼럼과 집계 함수에 사용될 수 있는 숫자형 데이터 칼럼들의 집합을 새로 만든다. 따라서 GROUP BY 절을 사용하게 되면 그룹핑 기준에 사용된 칼럼과 집계 함수에 사용될 수 있는 숫자형 데이터 칼럼들의 집합을 새로 만드는데, 개별 데이터는 필요 없으므로 저장하지 않는다. GROUP BY 이후 수행 절인 SELECT 절이나 ORDER BY 절에서 개별 데이터를 사용하는 경우 에러가 발생한다. 결과적으로 SELECT 절에서는 그룹핑 기준과 숫자 형식 칼럼의 집계 함수를 사용할 수 있지만, 그룹핑 기준 외의 문자 형식 칼럼은 정할 수 없다.

 

 

SELECT 문장과 ROWNUM 칼럼

오라클(Oracle)에서 순위가 높은 N개의 로우를 추출하기 위해 ORDER BY 절과 WHERE 절의 ROWNUM 조건을 같이 사용하는 경우가 있는데 이 두 조건으로는 원하는 결과를 얻을 수 없다. 위 Select 문의 실행 순서를 나타낸 표에서 강조 표시했듯이, Oracle의 경우 정렬이 완료된 후 데이터의 일부가 출력되는 것이 아니라, 데이터의 일부가 먼저 추출된 후(ORDER BY 절은 결과 집합을 결정하는데 관여하지 않음) 데이터에 대한 정렬 작업이 일어나므로 주의해야 한다.

SELECT ENAME, SAL 
FROM EMP
WHERE ROWNUM < 4
ORDER BY SAL DESC ;

예를 들어, 위 쿼리의 실행 결과는 급여 상위 3건을 출력한 것이 아니라, 급여 순서에 상관없이 무작위로 추출된 3건에 한해서 급여를 내림차순으로 정렬한 결과이므로 원하는 결과를 출력한 것이 아니다. 왜냐하면 ORDER BY 절이 사용되는 경우 ORACLE은 ROWNUM 조건을 ORDER BY 절보다 먼저 처리되는 WHERE 절에서 처리하기 때문이다. 따라서, 우리가 원하는 결과를 출력하려면 아래 예시와 같은 쿼리를 작성해야만 한다.

SELECT ENAME, SAL 
FROM ( SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC )
WHERE ROWNUM < 4 ;

정렬 후 원하는 데이터를 얻기 위해서는 서브쿼리인 인라인 뷰(Inline View)를 사용하여 데이터 정렬을 먼저 수행한 후 메인쿼리에서 ROWNUM 조건을 사용해야 한다. 다시 한번 실행 결과를 풀어서 설명하자면, ①EMP 테이블의 데이터를 급여가 많은 순서부터 정렬을 수행한 후 ②상위 3건의 데이터를 출력한 것을 알 수 있다. 추가로, 원하는 추출 결과와 동일한 순서로 정렬된 인덱스가 존재한다면 그 인덱스를 사용하여 동일한 결과를 얻을 수도 있다.