소트 연산의 종류와 동작 원리에 대해 알아보고 소트 연산을 피하고 부하를 줄여보자!
select *
from emp
order by deptno;
group by
명령과 order by
명령을 SQL문에 동시에 사용 시select deptno, sum(sal+nvl(comm,0))
from emp
group by deptno
order by deptno;
select /*+ gather_plan_statistics */ deptno, sum(sal+nvl(comm,0))
from emp
group by deptno;
HASH GROUP BY
연산으로 수행Sort Unique
연산과 Hash Unique
연산을 발생select /*+ gather_plan_statistics */ *
from dept
where deptno in (select deptno from emp);
IN
절에 의해 Sort Unique 연산
발생select /*+ gather_plan_statistics */ *
from emp
where mgr=7839
union
select *
from emp
where mgr=7566;
SORT UNIQUE
발생select /*+ gather_plan_statistics */ distinct job
from emp;
HASH UNIQUE
연산 사용 시 정렬 발생 Xselect /*+ gather_plan_statistics */ distinct job
from emp
order by job;
select /*+ gather_plan_statistics */ empno, ename, job, sal,
rank() over(partition by job order by sal desc)
from emp;
select /*+ gather_plan_statistics */ count(*), sum(sal), max(hiredate), min(hiredate)
from emp;
create index emp_x01 on emp(deptno);
select /*+ gather_plan_statistics */ *
from emp
order by deptno;
인덱스를 만들었으나, 테이블을 접근해 SORT ORDER BY 연산이 발생한다.
index(emp emp_x01)
로 힌트롤 줘도 똑같다.
왜냐하면 emp
테이블의 deptno
컬럼은 NULL
이 존재할 수 있기 때문이다.
select /*+ gather_plan_statistics */ *
from emp
where deptno is not null
order by deptno;
NULL
데이터를 결과 집합에 포함시키지 않아도 된다면 위의 방법을 사용하면 된다.
select /*+ gather_plan_statistics */ deptno, sum(sal+nvl(comm,0))
from emp
group by deptno;
정렬은 발생하지 않았으나, hash group by
연산이 발생했다.
order by 와 마찬가지로 not null을 넣어보자.
select /*+ gather_plan_statistics */ deptno, sum(sal+nvl(comm,0))
from emp
where deptno is not null
group by deptno;
인덱스를 스캔하면서, 같은 값으로 집계를 하였기 때문에 sort group by 연산을 사용하며 sort를 하지 않았기 때문에 nosort가 나온다.
집합 연산자
SORT UNIQUE
피하기union all
연산자를 사용IN절 안의 서브쿼리
SORT UNIQUE
피하기EXISTS
로 변경시, 해당 컬럼으로 인덱스를 사용 (사용 X시 무조건 성능 개선 X)unnest
는 서브 쿼리를 풀어 from절과 조인
소트 영역
은 로우 개수
와 함께 컬럼
들의 최종 길이
함께 결정
=> 가로 길이(컬럼 수)
와 세로 길이(로우 수)
가 함께 결정
SELECT
절에 있는 컬럼
의 수가 소트 영역
을 정하는 데 영향을 미침페이징 기법
: 사람이 볼 수 있을 만큼 적당히 나눠서 보여주는 기법
select a.*
from ( select rownum rn, a.*
from ( select *
from emp_100000 --emp 테이블을 10만배 복사
order by ename desc) a
) a
where a.rn between 1 and 10;
위 처럼 쿼리를 작성하면, sort order by도 발생하며 디스크
에서 정렬을 수행하게 된다.
select a.*
from ( select rownum rn, a.*
from ( select *
from emp_100000 --emp 테이블을 10만배 복사
order by ename desc) a
where rownum<=10
) a
where a.rn >=1;
where rownum<=10
을 통해 소트 영역을 적게 잡아두고 정렬을 수행하였다.
해당 쿼리로 인해 정렬에 필요한 메모리 공간으로 10개만 지정하고 그 안에서 정렬을 수행하는 것이다.
이때 count stopkey
가 실행계획에 나타나게 된다.
COUNT STOPKEY 원리
6번에서 이미 정렬되었으나, 오라클은 어떤 데이터가 입력될 지 모르기 때문에 멈추지 않는다.