SELECT 거래일시, 체결건수, 체결수량, 거래대금
FROM 종목거래
WHERE 종목코드 = ‘KR123456’
ORDER BY 거래일시
종목 코드 + 거래일시
순으로 구성하지 않으면 소트 연산을 생략할 수 없다.종목 코드 + 거래일시
인덱스를 사용한 경우 옵티마이저는 Sort Order By 오퍼레이션을 생략하게 된다.하지만 3-Tire 아키텍처는 서버 리소스를 수많은 클라이언트가 공유하는 구조이므로 클라이언트가 특정 DB 커넥션을 독점할 수 없다.
TOP 10
을 사용한다.SELECT TOP 10 거래일시, 체결건수, 체결수량, 거래대금
FROM 종목거래
WHERE 종목거래 = ‘KR123456’
AND 거래일시 >= ‘20180304’
ORDER BY 거래일시
FETCH FIRST 10 ROWS ONLY;
를 사용한다. SELECT 거래일시, 체결건수, 체결수량, 거래대금
FROM 종목거래
WHERE 종목거래 = ‘KR123456’
AND 거래일시 >= ‘20180304’
ORDER BY 거래일시
FETCH RISRT 10 ROWS ONLY
SELECT *
FROM ( SELECT 거래일시, 체결건수, 체결수량, 거래대금
FROM 종목거래
WHERE 종목거래 = ‘KR123456’
AND 거래일시 >= ‘20180304’
ORDER BY 거래일시 )
WHERE ROWNUM <= 10
종목코드 + 거래일시
순으로 구성된 인덱스 이용시, 소트 연산 생략후 인덱스를 스캔하다가 10개 레코드를 읽는 순간 멈춘다.COUNT(STOPKEY) = (TOP N Stopkey 알고리즘)
: 조건절에 부합하는 레코드가 아무리 많아도 그 중 ROWNUM 으로 지전한 건수만큼 결과 레코드를 얻으면 거기서 바로 멈춘다는 뜻0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 COUNT(STOPKEY)
2 1 VIEW
3 2 TABLE ACCESS (BY INDEX ROWID) OF ‘종목거래’ (TABLE)
4 3 INDEX (RANGE SCAN) OF ‘종목거래_PK’ (INDEX (UNIQUE))
SELECT *
FROM ( SELECT ROWNUM NO, A.*
FROM (
/* SQL BODY */
)
WHERE ROWNUM <= (:page * 10)
)
WHERE NO >= (:page-1) * 10 + 1
Top N
쿼리이므로 지정한 건수만큼 레코드를 업ㄷ으면 멈춘다SELECT *
FROM ( SELECT ROWNUM NO, A.*
FROM ( SELECT 거래일시, 체결건수, 체결수량, 거래대금
FROM 종목거래
WHERE 종목거래 = ‘KR123456’
AND 거래일시 >= ‘20180304’
ORDER BY 거래일시
)
WHERE ROWNUM <= (:page * 10)
)
WHERE NO >= (:page-1) * 10 + 1
0 SELECT STATEMENT Optimizer=ALL_ROWS
1 0 VIEW
2 1 COUNT(STOPKEY) -> NO STOP + STOPKEY
3 2 VIEW
4 3 TABLE ACCESS (BY INDEX ROWID) OF ‘종목거래’ (TABLE)
5 4 INDEX (RANGE SCAN) OF ‘종목거래_PK’ (INDEX)
COUNT(SROPKEY)
를 확인할 수 있다.WHERE ROWNUM <= (:page * 10)
는 불필요해 보인다.ROWNUM
은 단순한 조건절이 아닌, TOP N Stopkey 알고리즘을 작동하는 열쇠이다.COUNT(STOPKEY)
가 COUNT
로 변경된다.COUNT -> NO SORT + NO STOP
ROWNUM
을 빼먹지 말자Sort Aggregate
오퍼레이션이 나타난다.Sort Aggregate
는 전체 데이터를 정렬하진 않지만, 전체 데이터를 읽으면서 값을 비교한다.SELECT MAX(SAL) FROM EMP;
Execution Plan
-----------------------------------------------
0 SELECT STATEMENT Optimizer==ALL_ROWS
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF ‘EMP’ (TABLE)
CREATE INDEX EMP_X1 ON EMP(SAL);
SELECT MAX(SAL) FROM EMP;
Execution Plan
-----------------------------------------------
0 SELECT STATEMENT Optimizer==ALL_ROWS
1 0 SORT (AGGREGATE)
2 1 INDEX (FULL SCAN (MIN/MAX)) OF ‘EMP_X1’ (INDEX)
CREATE INDEX EMP_X1 ON EMP(DEPTNO, MGR, SAL);
SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30 AND MGR = 7698;
Execution Plan
-----------------------------------------------
0 SELECT STATEMENT Optimizer==ALL_ROWS
1 0 SORT (AGGREGATE)
2 1 FIRST ROW
3 2 INDEX (RANGE SCAN(MIN/MAX)) OF ‘EMP_X1’ (INDEX)
FIRST ROW
는 조건을 만족하는 레코드 1개를 찾을때 바로 멈춘다는 의미 = First Row Stopkey 알고리즘
CREATE INDEX EMP_X1 ON EMP(DEPTNO, SAL, MGR);
SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30 AND MGR = 7698;
CREATE INDEX EMP_X1 ON EMP(SAL, DEPTNO, MGR);
SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30 AND MGR = 7698;
First Row Stopkey
알고리즘은 작동한다.CREATE INDEX EMP_X1 ON EMP(DEPTNO, SAL
SELECT MAX(SAL) FROM EMP WHERE DEPTNO = 30 AND MGR = 7698;
First Row Stopkey
알고리즘이 작동하지 않는다.CREATE INDEX EMP_X1 ON EMP(DEPTNO, SAL);
SELECT *
FROM (
SELECT SAL
FROM EMP
WHERE DEPTNO = 30
AND MGR = 7698
ORDER BY SAL DESC
)
WHERE ROWNUM <= 1;
First Row Stopkey
또는 Top N Stopkey
알고리즘이 작동하게 구현하는 것이 고급 SQL 튜너에게 필요하다 - 그래서 내용이 어려운거 같다....SELECT 장비번호, 장비명, 상태코드
, ( SELECT MAX(변경일자)
FROM 상태변경이력
WHERE 장비번호 = P.장비번호 ) 최종변경일자
FROM 장비 P
WHERE 장비구분코드 = ‘A001’
장비번호 + 변경일자 + 변경순
순으로 구성돼 있기 때문에 가능한 일이다.책 p368
First Row Stopkey
알고리즘이 작동하지 않는다.First Row Stopkey
알고리즘이 작동하므로 성능은 비교적 좋다.Top N Stopkey
알고리즘이 작동하지 않아 성능은 느려질 수 있지만 쿼리 결과집합은 보장된다.Top N Stopkey
알고리즘도 작동한다.Row Limiting 절 도 12c 부터 지원한다. 추가적인 공부를 해보지
First Row Stopkey
와 Top N Stopkey
가 작동하게 SQL 를 작성하는 방식을 위주로 살펴보았지만 상황에따라 패턴이 달라질 수 있다.SELECT REGION, AVG(AGE), COUNT(*)
FROM CUSTOMER
GROUP BY REGION;
SELECT LPAD(상품번호, 30) || LPAD(상품명, 30) || LPAD(고객ID, 30) || LPAD(고객명, 30) || TO_CHAR(주문일시, ‘yyyymmdd hh24:mi:ss’)
FROM 주문상품
WHERE 주문일시 BETWEEN :START AND :END
ORDER BY 상품번호
SELECT LPAD(상품번호, 30) || LPAD(상품명, 30) || LPAD(고객ID, 30) || LPAD(고객명, 30) || TO_CHAR(주문일시, ‘yyyymmdd hh24:mi:ss’)
FROM (
SELECT 상품번호, 상품명, 고객ID, 고객명, 주문일시
FROM 주문상품
WHERE 주문일시 BETWEEN :START AND :END
ORDER BY 상품번호
)
SELECT *
FROM 예수금원장
ORDER BY 총예수금 DESC
SELECT 계좌번호, 총예수금
FROM 예수금원장
ORDER BY 총예수금 DESC
Top N 소트
알고리즘이 소트 연산 횟수와 Sort Area 사용량을 줄여주는 원리이다.Table Full Scan
방식 시 SORT ORDER BY STOPKEY
를 사용한다.where rownum
조건을 제거하면 Top N 쿼리가 아니게 된다.Top N 소트
알고리즘이 작동하지 않는다.rank
, row_number
함수는 max
함수보다 소트 부하가 적다Top N 소트
알고리즘이 작동하기 때문이다.