전체범위처리와 부분범위처리의 원리
출처 : 이화식(대용량데이터베이스솔루션) PPT자료
전체범위처리(Full Range Scan) | 부분범위처리(Partial Range Scan) |
---|---|
주어진 존건을 만족하는 전체 범위를 액세스하여 임시 저장공간에 저장 한 다음 필요한 가공을한 후 운반단위 만큼 추출 시키고 일단 정지 | 처리할 범위를 차레로 애게스하면서 필요한 추가적인 가공을 한 후 운반단위로 보냄.운반단위가 채워지면 수행을 멈추고 결과를 추출 |
주어진 조건의 범위가 넓은 경우 빠른 수행 속도를 기대할 수 없음 | 주어진 조건의 범위가 넓은경우도 그 범위중 일부만을 처리 하므로 빠른 수행속도를 보장 |
주의사항
{section}{column:width=50%}
부분범위처리의 자격 |
---|
{section}{column:width=33%}
SELECT SUM(ordqty)
FROM order
WHERE ord_date like '9503%'
{column}{column:width=33%}
SELECT ord_dept, COUNT(*)
FROM order
WHERE ord_date like '9503%'
GROUP BY ord_dept
{column}{section}
SELECT ord_dept, ordqty * 1000
FROM order
WHERE ord_date like '9503%;
ORDER BY ord_dept
SELECT deptno, empno
FROM emp1
WHERE sal > 1000000
UNION deptno, empno
FROM emp2
WHERE hiredate between '01-jan-90' and sysdate
SORT와 FILTER
{section}{column:width=50%}
옵티마이져 모드에 따른 부분범위 처리 |
---|
SELECT ord_dept, ordqty
FROM order
WHERE ord_dept > '1000'
SELECT *
FROM order
SELECT *
FROM order
ORDER BY item;
SELECT *
FROM order
WHERE ITEM>' ';
SELECT /*+ INDEX(ORDER ITEM_INDEX_NAME) */*
FROM order
WHERE ITEM>' ';
넓은범위의 처리보다 좁은범위의 처리가 빠른 경우
SELECT *
FROM order
WHERE ordno BETWEEN 1 and 1000
AND custno like 'DN%';
출처 : 이화식(대용량데이터베이스솔루션1)
1. ORDNO 인덱스에서 조건을 만족하는 첫번째 로우를 B*TREE 형식으로 찾는다
2. 인덱스에 있는 ROWID를 이용하여 ORDER 테이블의 해? 로우를 액세스한다
3. 액세스된 테이블의 로우에 있는 CUTOSNO가 'DN'으로 시작하는지를 검증하여 만족하는 로우만 운반단위로 보낸다. 즉, CUSTNO는 인덱스를 사용하지 않고 검증 기능으로만 사용되었다
4. ORDNO 인덱스의 다음 로우를 액세스하여 2~3을 반복하여 운반단위가 채워지거나 ORDNO 인덱스의 처리범위가 끝나면 수행을 멈춘다
==> 'WHERE ordno BETWEEN 1 and 1000' 을 만족하는 로우가 1,000건이므로 최대 1,000회의 처리를 해야한다. 더구나 CUSTNO like 'DN%'를 만족하는 로우는 10건이라고 가정했으므로 ORDNO 인덱스를 경유해 액세스한 1,000건의 로우들은 거의가 이 조건을 만족하지 못할 것이므로 좀처럼 운반단위를 채울수가 없어 계속해서 다음 건을 수행해야 하며 최악의 경우 ORDNO의 모든 범위(1,000)을 완료해야만 멈출 수 있다.
출처 : 이화식(대용량데이터베이스솔루션1)
1. CUSTNO 인덱스에서 조건을 만족하는 첫번째 로우를 B*TREE 형식으로 찾는다.
2. 인덱스에 있는 ROWID를 이용하여 ORDER 테이블의 해당 로우를 액세스한다
3. 액세스된 테이블의 로우에 있는 ORDNO가 1RHK 1,000사이에 있는지를 검증하여 만족하는 로우만 운반단위로 보낸다. 즉, ORDNO의 범위는 넓으므로 쉽게 조건을 만족할 수가 있어 운반단위로 보낼 수 있는 확률이 높아지는 것에 유의
==> 'CUSTNO LIKE DN%'을 만족하는 로우가 10건이라고 가정했으므로 최대 10회만 처리하면 된다. 더구나 'ORDNO BETWEEN 1 AND 1000'을 만족하는 로우는 1,000건이라고 가정했으므로 CUSTNO 인덱스를 경유해 액세스한 로우들은 거의가 이 조건을 만족하게 되어 쉽게 운반단위를 채울 수가 있다. 최악의 경우 운반단위를 채울 수가 없더라도 CUSTNO의 모든범위는 10건에 불과하므로 언제나 빠른 수행속도가 보장
결론
1. 액세스를 주관하는 컬럼의 처리범위는 좁을수록 유리 => 그 외 컬럼들의 처리 범위에 영향을 적게 받으므로 언제나 빠른 수행속도를 보장
2. 액세스를 주관하는 컬럼의 범위가 넓더라도 그 외의 조건을 만족하는 범위가 넓다면 역시 빠른 수행속도를 보장 => 그 외의 조건들이 좁은 범위를 가진다면은 수행속도가 더 늦어 짐
3. 액세스 주관 컴럼의 범위가 넓고 그 외 컬럼의 범위가 좁아서 늦어지는 경우는 처리범위가 좁은 컬럼이 액세스 주관 컬럼이 되도록 하면 해결. 옵티마이져는 주어진 조건에 따라 항상 좁은 처리범위를 가진 컬럼을 사용도록 실행계획을 수립하나 옵티마이져 모드나 비교된 컬럼의 분포도에 따라, 혹은 작성된 SQL에 따라 그렇지 못한 경우가 발생할 수 있다. => 힌트를 사용하여 원하는 수행 속도를 얻을 수 있다
액세스 주관 조건의 범위 | 검증조건의범위 | 수행속도 | 조치사항 |
---|---|---|---|
좁다 | 좁다 | 양호 | |
좁다 | 넓다 | 양호 | |
넓다 | 좁다 | 불량 | 주관조건과 검증조건의 역할을 교체 |
넓다 | 넓다 | 양호 |
h3.4.4 부분범위처리로의 유도
인덱스나 클러스터를 이용한 SORT의 대체 |
---|
인덱스만 액세스한는 부분범위처리 |
---|
MAX의 처리 |
---|
{CODE:SQL}
SELECT /*+ INDEX_DESC(A INDEX1) */
SEQ+1
FROM PRODUCT A
WHERE DEPT='12300'
AND JOB='부장'
AND ROWNUM = 1;
{CODE}
EXISTS를 활용한 부분범위처리 |
---|
{section}{column:width=33%}
출처 : 이화식(대용량데이터베이스솔루션) PPT자료
{column}{column:width=33%}
* 왼쪽은 조건을 where절에 기술하고 그 결과를 count하여
변수에 저장한 후에 'IF CNT>0'과 같은 조건으로 다음 처리를 진행.
SQL은 원하는 집합을 요구하는 것이므로 그 결과가 한 건이든지 수천 건이든지
모두 처리하여 COUNT를 한 후 최종적으로 하나의 결과를 추출
* 오른쪽은 EXISTS를 사용하면 뒤에 있는 서브쿼리가 부분범위처리로 수행하다가
조건을 만족하는 첫번째 로우를 만나는 순간 서브쿼리의 수행을 멈추고 메인쿼리를 수행
{column}{section}
{section}{column:width=33%}
SELECT ord_dept, ord_date, custno
FROM prodcut
WHERE ord_date like '95%'
MINUS
SELECT ord_dept, ord_date, 'DN01'
FROM sale
WHERE custno = 'DN01'
=> 위의 SQL은 다량의 처리범위를 각각의 로우마다 랜덤 액세스로 대응되는 로우를 찾아 확인하는 것을
피하기 위해 전체 처리가 최적화(ALL_ROWS)되도록 Merge 방법으로 유도한 경우이다. 전체범위로 처리되므로
온라인에서는 첫번째 운반단위가 추출되는 시간이 많이 소요
{column:width=33%}
SELECT ord_dept, ord_date, custno
FROM product x
WHERE ord_date like '95%'
AND NOT EXISTS(SELECT * FROM SALE y
WHERE y.ord_dept = x.ord_dept
AND y.ord_date = x.ord_date
AND y.custno = 'DNO1')
==> 서브쿼리가 부분범위 처리로 바뀌어서 처리속도가 개선 되었다
{column}{section}
'NOT EXISTS'를 요구했으므로 서브쿼리의 지밥이 적을수록 조건을 만족하는 범위는 넓어지게 된다. 그러므로 custno='DN01'을
만족하는 로우가 적다면 아주 빠른 수행 속도를 보장받을 수 있고, 그렇지 않다면 'MINUS'를 사용한 SQL이 더 유리
ROWNUM의 활용 |
---|
출처 : 이화식(대용량데이터베이스솔루션1)
SELECT *
FROM product
WHERE dept like '12%'
AND qty > 0
AND ROWNUM <= 10
ORDRE BY item;
출처 : 이화식(대용량데이터베이스솔루션1)
출처 : 이화식(대용량데이터베이스솔루션1)
{section}{column:width=33%}
CREATE VIEW prod_view(dept, totqty)
AS SELECT dept, sum(qty)
FROM product
GROUP BY dept;
{column}{column:width=33%}
SELECT rownum, dept, totqty
FROM prod_view
WHERE dept like '123%'
AND rownum <= 10;
{column}{section}
출처 : 이화식(대용량데이터베이스솔루션1)
SELECT rownu, dept, totqty
FROM (SELECT DEPT, SUM(QTY) as totqty
FROM PRODUCT
WHERE dept like '123%'
GROUP BY dept)
WHERE rownum <= 10;
{column}{column:width=33%}
SELECT dept, totqty
FROM (SELECT ROWNUM as RNUM, dept, totqty
FROM (SELECT dept, SUM(qty) as totqty
FROM product
WHERE dept like '123%' GROUP BY dept))
WHERE RNUM=5
AND ROWNUM=1
==> 조건절 ROWNUM=1조건을 추가해야만 불필요한 처리를 없앴을 수 있다. 만약 이 조건이 없다면 RNUM=5인 로우를 찾았더라도 멈추지 않고 FROM뒤에 기술한 인라인 뷰의 모든 로우들이 끝날때까 수행하게 된다
{column}{section}
SQL의 이원화를 통한 부분범위 처리 |
---|
* 부서코드가 '11'로 시작하는 모든 사원들의 년간 급여액을 추출
SELECT 부서코드, 사번, SUM(본봉), NVL(SUM(수당),0)
FROM 급여테이블
WHERE 부서코드 LIKE '11%'
AND 급여일 BETWEEN '940101' AND '941231'
GROUP BY 부서코드, 사번
==> *11로 시작하는 부서를 가진 사람들이 아주 많다면 온라인 어플리케이션에서 원하는 수행속도를 얻을 수 없음*
{section}{column:width=33%}
SELECT 부서코드 ITNO :DEPTNO
FROM 부서테이블
WHERE 부서코드 LIKE '11%'
==> 일반적으로 급여테이블에 비해서 부서테이블은 로우가 작으로 11로 시작하는 부서코드를 먼저 찾는다
{column}{column:width=33%}
SELECT 사번, SUM(본봉), NVL(SUM(수당),0)
FROM 급여테이블
WHERE 부서코드 = :deptno
AND 급여일 BETWEEN '940101' AND '941231'
GRUOP BY 사번;
* 위의 방법은 처리가 넓은 급여테이블에서 '11'로 시작하는 부서코드를 가진 모든 데이터를 읽지 않고 특정부서만 '='로 읽게 함으로써
실제로는 처리범위의 일부분만 액세슷하도록 하여 부분범위처리로 유도한 것
{column}{section}