화투.  일명 동양화...  --;;

얼마전 아버님 친구분들이 오셔서 잠깐 동양화를 치셨나 부다.
그뒤로 현준이는 화투를 꺼내달라고 한단다...
꺼내서는 가지런히 모아놓은 화투패를 바닥에 던진다. 촤악~~~~
(흠.. 던지는걸 좋아한단 말이지...)

이왕 던져진거 어머님과 아버님은 몇가지 가르쳐 주셨나부다.
그중에 "비"가 맘에 들었는지 그 많은 패중에서
비 어딨어? 하고 물으면 냉큼 집어 낸다고 한다..
(이런이런...  이걸 좋아해야해 말아야해... )


주말에 현준이는 아빠에게 또 화투를 꺼내달라 했다.
꺼내준 아빠.
또 촤악~  던지는 현준.
아빠는 이번에 "똥"을 가르쳐 주었나 부다.
현준이에게 차근차근 설명하는 아빠...
"기저귀에 있는 똥이랑 저 똥이랑 같은 똥이야~"


저녁에 온가족이 모였는데..
우리 현준이는 그동안 갈고 닦은 실력(?)을 유감없이 발휘해 줬다...
48개 패중에서 "비"와 "똥" 골라내기.. ㅋㅋ

아 얘가 커서 머가 되려나.. --a




Posted by 항아리고미
ORACLE Tip2008. 11. 17. 15:19

<형식>
SELECT 컬럼명,그룹함수(컬럼명), GROUPING(컬럼명)
FROM 테이블명
WHERE 조건
GROUP BY [ROLLUP | CUBE] 그룹핑하고자하는 컬럼명, ...
[GROUPING SETS (컬럼명,컬럼명, ...), ...]
HAVING 그룹조건
ORDER BY 컬럼명 또는 위치번호 

ROLLUP과 CUBE

ROLLUP과 CUBE는 매우 유사하다.  이들은 우리가 GROUP BY한 결과에 대해 여러가지 형태의 소계를 쉽게 구해준다.
ROLLUP은 GROUP BY 절의 그룹 조건에 따라 전체 행을 그룹화 하고, 각 그룹에 대해 부분합을 구하는 연산자이다.
CUBE는 ROLLUP에 의한 그룹 결과와 GROUP BY 절에 기술된 조건에 따라 그룹 조합을 만드는 연산자이다.
즉, ROLLUP 연산자를 수행한 결과에 더해 GROUP BY 절에 기술된 조건에 따라 모든 가능한 그룹핑 조합에 대한 결과를 출력한다.

- ROLLUP과 CUBE는 GROUP BY 절 뒤에 기술한 컬럼 개수에 따라 출력되는 결과 셋이 달라진다.
- GROUP BY 뒤에 기술한 컬럼이 2개일 경우 ROLLUP은 n+1에서 3개의 그룹별 결과가 출력되고, CUBE는 2*n에서 2*2=4개의 결과 셋이 출력된다.

ROLLUP 예제>
select deptno, job, sum(sal), grouping(deptno), grouping(job)
from emp
group by rollup(deptno, job)

DEPTNO JOB SUM(SAL) GROUPING(DEPTNO) GROUPING(JOB)
10 CLERK     920 0 0
10 MANAGER   2572.5 0 0
10 PRESIDENT 5500 0 0
10   8992.5 0 1
20 ANALYST   3450 0 0
20 MANAGER   3123.75 0 0
20   6573.75 0 1
30 SALESMAN  2912.5 0 0
30   2912.5 0 1
    18478.75 1 1

CUBE 예제>
select deptno, job, sum(sal), grouping(deptno), grouping(job)
from emp
group by cube(deptno, job)

DEPTNO JOB SUM(SAL) GROUPING(DEPTNO) GROUPING(JOB)
    18478.75 1 1
  ANALYST   3450 1 0
  CLERK     920 1 0
  MANAGER   5696.25 1 0
  PRESIDENT 5500 1 0
  SALESMAN  2912.5 1 0
10   8992.5 0 1
10 CLERK     920 0 0
10 MANAGER   2572.5 0 0
10 PRESIDENT 5500 0 0
20   6573.75 0 1
20 ANALYST   3450 0 0
20 MANAGER   3123.75 0 0
30   2912.5 0 1
30 SALESMAN  2912.5 0 0

 

Grouping 함수

GROUPING함수는 ROLLUP이나 CUBE 연산자와 함께 사용하여 GROUPING 함수에 기술된 컬럼이 그룹핑 시 즉, ROLLUP이나 CUBE 연산시 사용이 되었는지를 보여 주는 함수이다.
특별히 연산 기능은 없으며 ROLLUP이나 CUBE 연산 후 출력된 결과에 대한 사용자의 이해를 높이기 위해 사용된다.
즉, GROUPING 함수를 이용할 경우 출력되는 결과값 중 NULL값이 있다면 이 NULL값이 ROLLUP이나 CUBE 연산의 결과로 생성된 것인지, 원래 테이블상에 NULL값으로 저장된 것인지를 확인할 수 있다.

GROUPING Function은 ROLLUP, CUBE Operator에 모두 사용할 수 있습니다.

GROUPING Function는 해당 Row가 GROUP BY에 의해서 산출된 Row인 경우에는 0을 반환하고,
ROLLUP이나 CUBE에 의해서 산출된 Row인 경우에는 1을 반환하게 됩니다.
따라서 해당 Row가 결과집합에 의해 산출된 Data인지, ROLLUP이나 CUBE에 의해서 산출된 Data인지를 알 수 있도록 지원하는 함수입니다.

- GROUPING 함수는 인수 로 하나의 값만을 가질 수 있다.
- GROUPING 함수에 사용된 인수는 GROUP BY 절에 기술된 값중에 하나와 반드시 일치되어야 한다.



GROUPING SETS 함수

GROUPING SETS 함수는 GROUP BY 절에서 그룹 조건을 여러 개 지정할 수 있는 함수이다.
GROUPING SETS 함수의 결과는 각 그룹 조건에 대해 별도로 GROUP BY한 결과를 UNION ALL한 결과와 동일하다.
GROUPING SETS 함수는 하나의 SQL문에 의해 여러 개의 그룹 조건을 한꺼번에 지정하여 복잡한 그룹 처리 과정을 단순하게 구성할 수 있다.

GROUPING SETS 함수는 Group by의 확장된 형태로 하나의 쿼리문에서 원하는 그룹핑 조건을 여러 개 기술할 수 있으며,
GROUPING SETS 함수 사용이 불가능한 이전 버전에서 복잡한 union all 연산자를 사용하여 기술하던 것을 간단하게 한 문장 안에서 해결할 수 있어 검색시 효율성이 증대 된다.
다시 말해서, GROUPING SETS 함수를 사용하면, group by ... union all을 사용한 것보다 SQL 문이 간단해지고 또한 실행시 성능이 빨라진다.

GROUPING SETS 예제>
select deptno, job, ename, sum(sal), grouping(deptno), grouping(job), grouping(ename)
from emp
group by grouping sets((deptno, job), (deptno, ename))

DEPTNO JOB ENAME SUM(SAL) GROUPING(DEPTNO) GROUPING(JOB) GROUPING(ENAME)
10 CLERK       920 0 0 1
10 MANAGER     2572.5 0 0 1
10 PRESIDENT   5500 0 0 1
20 ANALYST     3450 0 0 1
20 MANAGER     3123.75 0 0 1
30 SALESMAN    2912.5 0 0 1
10   CLARK      2572.5 0 1 0
10   KING       5500 0 1 0
10   MILLER     920 0 1 0
20   CHAN       3450 0 1 0
20   JONES      3123.75 0 1 0
30   ALLEN      1600 0 1 0
30   MARTIN     1312.5 0 1 0

Posted by 항아리고미
책장2008. 11. 17. 10:25


2008.11.14  ★★★★★

얼마전 라디오에서 보험에 연장정기제도라는 것이 있다고 하길래..
보험에 대해 알아보고자 책을 찾던중 흥미를 끄는 제목이 있어서 읽어본 책.

2000년인가..  보험을 들때 아무런 생각없이 머리속이 하얗게 되어서 들었던 나에게
하얗던 머릿속을 속속들이 채워준 책이다.
평생교육이라고..  역시 사람은 모르면 배워야 한다..

그런데...
읽으면서 너무 나도 아쉬웠던건..
좋은 상품도 개중에는 있을텐데..  너무 편협하게 보험회사를 몰아세우면서 썼다는거...
동전의 앞뒤가 있듯.
좋은면이 있으면 나쁜면이 있기 마련이지만..
보험의 나쁜면만을 너무너무 파는 책이다 보니..  좋은면도 내심 궁금해지더군..
Posted by 항아리고미
ORACLE Tip2008. 11. 14. 10:30

* 인덱스 유일 스캔 (INDEX UNIQUE SCAN)
  - 대부분 단 하나의 ROW를 추출
  - 전체조건을 만족할 경우 옵티마이져는 인덱스 유일 스캔을 선택
    - 인덱스가 기본키 이거나, 유일 인덱스(UNIQUE INDEX)로 구성
    - 인덱스를 구성하는 모든 컬럼들이 모두 조건절에서 '='(EQUAL) 비교
  - 데이터베이스 링크(DATABASE LINK) 사용시 힌트로 적용
  - 힌트는 INDEX(TABLE_ALIAS INDEX_NAME) 힌트 적용
 
* 인덱스 범위 스캔 (INDEX RANGE SCAN)
  - 추출되는 ROW는 INDEX 구성 컬럼의 정렬순서와 동일
  - ORDER BY 절이 있더라도 추가 정렬 작업이 필요없을 수도 있음.
  - NON UNIQUE INDEX, UNIQUE INDEX
    - 하나이상의 인덱스 선행컬럼에 상수나 변수로 조건이 부여되어야 함.
    - 비교연산자는 '=, <, <=, >, >=, BETWEEN, LIKE'등
    - 단, LIKE연산자 사용시 '%ABC'의 경우 범위 스캔 불가
    - COL1+COL2+COL3에서 COL2 조건이 없는 경우
  - 힌트는 INDEX(TABLE_ALIAS INDEX_NAME) 힌트 적용

* 인덱스 역순 범위 스캔 (INDEX RANGE SCAN DESCENDING)
  - 인덱스를 역순으로 스캔
  - 기타 사항에 대하여는 인덱스 범위 스캔과 동일
    - 가장 최근에 발생한 내용을 처리하기 위한 경우 사용
    - 부분범위 처리 (Partial Range)를 위해 사용
    - ORDER BY .. DESC 시 발생
    - INDEX_DESC(TABLE_ALIAS INDEX_NAME) 힌트 사용시 발생

* 인덱스 스킴 스캔 (INDEX SKIP SCAN)
  - ORACLE 9i 부터 적용
  - Cardinality가 낮은 선형 컬럼 + 높은 후행칼럼으로 구성된 인덱스일수록 큰 효과
  - 내부적으로 선행 컬럼 값의 Distinct Value 만큼의 Logical Sub-Index로 나눠서 SCAN한다.
  - Analyze 되어 있는 오브젝트에 적용된다.     
  - 힌트는 INDEX_SS, INDEX_SS_ASC, INDEX_SS_DESC 가 있다. 
 
* 인덱스 전체 스캔 (INDEX FULL SCAN)
 - 전제조건
  - 조건절에서 인덱스 컬럼에 적어도 하나이상 사용되었을때.
  - 반드시 선행컬럼이 사용될 필요는 없음.
  - 쿼리 내 사용된 어떤 테이블들의 모든 컬럼들이 인덱스에 존재
  - 인덱스 컬럼 중 최소한 NOT NULL인 컬럼이 최소 하나는 존재
  - ORDER BY 절에 사용될 경우 인덱스를 사용하여 SORT가 가능할 때
 - SINGLE BLOCK I/O 수행
 
* 인덱스 고속 전체 스캔 (INDEX FAST FULL SCAN)
 - 인덱스 스캔만을 하며, 테이블 엑세스는 하지 않음.
 - MULTI BLOKC I/O 를 수행
 - BITMAP INDEX에서는 적용 불가
 - 반드시 선행 컬럼이 사용될 필요는 없음
 - 연관된 힌트는 INDEX_FFS, NO_INDEX_FFS 가 있다.

출처 : 새로쓴 대용량 데이터베이스 솔루션 vol.1

Posted by 항아리고미


* 꿀간장닭조림
주재료 : 닭(1/2), 고구마(3줌)
고기밑간 : 소금, 후춧가루, 청주
꿀간장닭조밀 부재료 : 버터(1/2), 청량고추(1개), 홍고추(1개), 다진마늘(1)
꿀간장닭조림 양념장재료 : 간장(5), 물(5), 맛술(3), 꿀(3), 생강가루(약간), 참기름(0.5), 통깨(0.5), 실파(적당량)
버터를 두르고 밑간을 한 닭과 고구마를 넓게 펼쳐 팬에 깔고 뚜껑을 닫고 푹~  중불에서 노릇하게 익혀줍니다.
고구마와 닭을 완전히 익혀줍니다.
팬에 기름을 두르고 편으로 썬 마늘, 홍고추, 청량고추를 넣어 볶아준다. (아이꺼는 고추생략)
양념장재료 넣고 팔팔 끓여 소스를 만들고 익혀둔 고구마와 닭을 넣고 조려준다. 마지막으로 참깨와 통깨 뿌리고 끝.



> 기대했던 만큼보다는 별로..
> 고구마를 많이 넣어서 그런가..
> 소스가 조금 남아있을 정도로 익혀놨다가 먹기전에 살짝 데운다는것이..
> 소스가 쫄아 들었다.. --;;;
> 그래도 맛나게 먹어준 신랑에게 감사...

* 오이볶음
주재료 : 오이(1개), 굵은 소금(0.5)
양념재료 : 다진마늘(0.5), 설탕(0.3), 참기름(0.5), 꺠소금(0.5), 후춧가루(약간)
오이를 동그랗게 모양을 살려 두께를 얇게 썰어주고 굵은 소금(0.5) 넣고 30분간 절여줌.
절인 오이 물기를 아주 꼭~ 짜서 놓고 달군팬에 기름+마늘넣고 볶다가 양념하면 끝.

> 오이를 조금 색다르게 먹어보고파서 했는데.....
> 실패실패.. 
> 나의 손맛은 언제쯤 생길까..??  에혀~

이거다 둥이맘에서 퍼온 레시피임.

Posted by 항아리고미
책장2008. 11. 13. 14:34


2008.11.13 ★★★★

요즘 드라마 베토벤바이러스를 즐겁게 보다가 클래식에 대한 책이 있길래 읽어봤다.
부담없는 설명과 곡이 나오게 된 배경등을 그림과 함께 수록해서 쉽게 읽을수 있는책이다. 
클래식에 대한 상식이 좀 생겼나.. 으쓱~ ^^

여기에 소개된 곡들에 대해서 한번씩은 꼭 들어보리.. 


Posted by 항아리고미
ORACLE Tip2008. 11. 13. 11:02
1. NESTED LOOPS

     Rows   Execution Plan
    ------- -----------------------------------------------------
④    7701   NESTED LOOPS
① 148946     TABLE ACCESS (FULL) OF 'ITEM_BASE'
③    7719     TABLE ACCESS (BY INDEX ROWID) OF 'CS_SPEC'
②    7724       INDEX (UNIQUE SCAN) OF 'PK_CS_SPEC'

① 'ITEM_BASE'를 전체테이블 스캔으로 액세스한 로우 수는 148946건.
    이중에서 조건절을 통과한 로우수는 7724건. 
    ②에서 'PK_CS_SPEC'인덱스에 연결을 시도한 회수를 보고 알아낼수 있다.
② 선행 테이블의 조건을 통과한 7724건이 'CS_SPEC' 테이블의 기본키를 이용하여 연결을 시도 
    그중에서 5건을 실패 이것은 ③에 나타난 7719 라는 숫자를 보고 알수 있다.
    그 이유는 인덱스를 성공적으로 액세스한 것만 테이블을 액세스하러 갔기 때문이다.
③ 기본키의 ROWID로 테이블을 액세스 하였다.
    그런데 나중에 수행된 'CS_SPEC'테이블에도 체크조건이 있음을 짐작할 수 있다.
    그 이유는 ④에 나타난 숫자인 7701을 보면 체크조건에 의해 18건이 걸러졌음을 짐작할 수 있다.
④ 조인의 최종 결과가 7701건임을 의미한다.

 
2. OUTER JOIN  

     Rows   Execution Plan
    ------- -----------------------------------------------------
④      280  NESTED LOOPS (OUTER)
②    74861   TABLE ACCESS (BY INDEX ROWID) OF 'BAL_ITEM'
①  210991      INDEX (RANGE SCAN) OF 'PK_BAL_ITEM' (UNIQUE)
③   53200    TABLE ACCESS (FULL) OF 'TPF_INFO'

① 'BAL_ITEM' 테이블의 기본키를 범위처리로 스캔하면서 인덱스에 있는 ROWID로 테이블을 엑세스한다.
     이렇게 스캔한것은 총 210991 건이지만 실제로 테이블을 액세스한 것은 74861건이다. 
     그 이유는 최소 두 개 이상의 컬럼에 조건이 부여되었지만 이들이 결합 인덱스로 구성된 기본키에서 연속된 순서를
     가지고 있지 않다는 것을 나타낸다.
②  이 테이블을 액세스한 74861건 중에서 체크조건에 의해서 다시 걸러지고 남은건은 280건이다.
     연결고리에 인덱스가 없기 때문에 연결대상마다 매번 전체테이블 스캔을 하였다.
     이 조인은 아우터 조인이기 때문에 설사 연결에 실패했더라도 조인은 언제나 성공이므로 조인결과 집합인 280과 동일하다.
③  이 테이블을 스캔한 로우수는 53200이지만 이테이블과의 연결을 시도한 횟수는 280이다.
     즉, 테이블의 총 로우수는 190 (53200/280) 건이다.
④  연결을 시도한 280건이 아우터 조인에 의해서 모두 성공하게 되므로 최종결과는 280건이다.

출처 : 새로쓴 대용량 데이터베이스 솔루션 vol.1
Posted by 항아리고미
ORACLE Tip2008. 11. 13. 10:00

뷰 병합 (View Merging) 
: 뷰쿼리를 엑세스쿼리에 병합해 넣는 방식

* 일반적인 뷰병합

 뷰  뷰쿼리  뷰병합
 CREATE VIEW emp_10
(e_no, e_name, job, manager,
salary, commission, deptno)
AS
SELECT empno, ename, job, mgr, sal,
 comm, deptno
FROM emp
WHERE deptno = 10;
SELECT e_no, e_name, salary, deptno
FROM emp_10
WHERE salary > 1000000;

SELECT empno, ename, sal, hiredate
FROM emp
WHERE deptno = 10
  AND sal > 1000000;

엑세스쿼리를 기준으로 뷰쿼리의 대응인자를 병합
- 엑세스쿼리에 있는 뷰를 원래 테이블인 emp로 변환
- 남아있는 조건절을 다시 엑세스쿼리에 병합
- 컬럼들도 대응되는 원래 테이블의 컬럼들로 병합

* View Merging이 불가능한 경우 : 엑세스쿼리에 있는 조건들을 뷰쿼리에 진입(Pushing predicate)
- 집합연산(UNION, UNION ALL, INTERSECT, MINUS)
- CONNECT BY
- ROWNUM을 사용한 경뷰우
- SELECT-List의 그룹함수(AVG, COUNT, MAX, MIN, SUM)
- GROUP BY , SELECT-List의 DISTINCT : 단, Merge힌트를 사용했거나 관련 파라미터가 Enable이면 뷰 병합 가능

* Pushing predicate : 뷰병합을 할 수 없는 경우를 대상으로 뷰쿼리 내부에 엑세스쿼리의 조건절을 진입
 뷰 뷰쿼리  뷰병합 
 CREATE VIEW emp_union_view
 (e_no, e_name, job, mgr, sal, comm, deptno)
AS
 SELECT empno, ename, job, mgr, sal, comm, deptno
 FROM regular_emp
 UNION ALL
 SELECT empno, ename, job, mgr, sal, comm, deptno
 FROM temporary_emp
SELECT e_no, e_name, mgr, sal
FROM emp_union_view
WHERE deptno = 20;
 SELECT empno, ename, mgr, sal
FROM (
   SELECT empno, ename, mgr, sal
   FROM regular_emp
   WHERE detpno = 20
   UNION ALL
   SELECT empno, ename, mgr, sal
   FROM temporary_emp
   WHERE 90 = 20

* GROUP BY 뷰의 병합 (Pushing predicate Merge)
 뷰 뷰쿼리  뷰병합 
CREATE VIEW emp_group_by_deptno
AS
SELECT deptno, AVG(sal) avg_sal, MIN(sal) min_sal, MAX(sal) max_sal
FROM emp
GROUP BY deptno
SELECT e_no, e_name, mgr, sal FROM emp_group_by_deptno WHERE deptno = 10 SELECT deptno, AVG(sal) avg_sal, MIN(sal) min_sal, MAX(sal) max_sal
FROM emp
WHERE deptno = 10;
GROUP BY deptno   
위의 작업이 가능하려면 아래의 파라미터가 Enable 되어야 한다.
- complex_view_merging = enable
- Optimizer_secure_view_merging = enable

출처 : 새로쓴 대용량 데이터베이스 솔루션 vol.1

Posted by 항아리고미
책장2008. 11. 12. 14:39



2008.10  ★★★

중국역사 책이라고는 삼국지 밖에 읽어본적이 없던 내가 재미있게 읽었던 책.
황제 뒷담화라고 해야하나. 황제와 엮인 역사의 흥미로운 이면을 보여주고 있다.
인간의 탐욕과 권력의 끝에 황제가 있더군... 

그리고 삼국지를 읽었을때도 느꼈던 것이지만...
중국은 정말 사람도 많고 땅도 넓다는거다..
Posted by 항아리고미
ORACLE Tip2008. 11. 12. 14:05

질의변환의 목적은 옵티마이져가 보다 양호한 실행계획을 얻을 수 있도록 가능한 최대한 적절하게 SQL 형태를 변환하는 것

예1>
① sales_qty > 1200/12
② sales_qty > 100
③ sales_qty * 12 > 1200

①과 ②는 동일하게 취급.
③은 연산을 통하여 ②와 동일한 조건을 만들지 않는다. (소수점 등의 문제가 있음)
 
예2>
① job like 'SALESMAN'      
② job = 'SALESMAN' 

①과 ②는 동일하게 취급 단, 가변길이 타입만 가능하다. 

예3> 
① job IN ('CLERK', 'MANAGER')  
② job = 'CLERK' OR job='MANAGER' 

① sales_qty > ANY (:in_qty1, :in_qty2) 
② sales_qty > :in_qty1 OR sales_qty > :in_qty2

① WHERE 1000000 > ANY (SELECT sal FROM emp WHERE job='CLERK')
② WHERE EXISTS (SELECT sal FROM emp WHERE job = 'CLERK' AND 1000000 > sal)

①을 ②와 같은 형식의 조건절로 확장시킨다. 

예4> 
① sales_qty > ALL (:in_qty1, :in_qty2)
② sales_qty > :in_qty1 AND sales_qty > :in_qty2

①을 ②와 같은 형식의 조건절로 확장시킨다. 

① WHERE 100000 > ALL (SELECT sal FROM emp WHERE job='CLERK')
② WHERE NOT (1000000 <= ANY (SELECT sal FROM emp WHERE job = 'CLERK'))
③ WHERE NOT EXISTS (SELECT sal FROM emp WHERE job = 'CLERK' AND 1000000 <= sal)

①을 ②, ③과 같은 형식의 조건절로 확장시킨다. 

예5>
① sales_qty BETWEEN 100 AND 200
② sales_qty >= 100 AND sales_qty <= 200

①을 ②와 같은 형식의 조건절로 확장시킨다. 

NOT (sal <30000 OR comm IS NULL) 
NOT sal <30000 AND comm IS NOT NULL
③ sal >= 30000 AND comm IS NOT NULL

①을 ②로 변환하고 이것을 다시 ③으로 변환한다.

예6>
① NOT deptno = (SELECT deptno FROM emp WHERE empno=7689)
② deptno <> (SELECT deptno FROM emp WHERE empno=7689)
 
반대 비교연산을 찾아 대체시키는 변환을 한다.


이행성 규칙 (Transitivity principie)
: 쿼리변환의 한 경우 (비용기준 옵티마이져에서만 가능)

1. A = B and B = C 이면 A = C
WHERE column1 comparision_operators constant AND column1 = column2
=> column2 comparison_operators constant
comparision_operators : =, !=, ^=, <, <>, >, <=, >=
constant : 연산, SQL 함수, 문자열, 바인드 변수, 상관관계 변수를 포함하는 상수 수식

SELECT *
FROM emp e, dept d
WEHRE e.deptno = 20
  AND e.deptno = d.deptno;
=> d.deptno = 20 을 추론 
만약 e.deptno 인덱스가 없다면 EMP 테이블을 전체 테이블 엑세스를 하면서 매번 dept 테이블 연결
이행성 규칙에 의해 실행계획이 DEPT 테이블을 먼저 인텍스로 엑세스하는 실행계획이 가능

* 비교값이 상수 수식이 아닌 컬럼이라면 이행성 규칙은 적용되지 않는다.
WHERE column1 comparision_operators column3 AND column1 = column2
=> (X) column2 comparison_operators column3

2. OR 조건들의 UNION ALL 분기
: UNION ALL로 각각의 인덱스를 경유하는 실행계획을 수립하고 이를 결합
변환기준
- OR를 사용한 조건절을 분기시켰을 때 각각이 인덱스 접근 경로로 이용할 수 있다면 변환을 수행
- 인덱스 사용불가로 전체 테이블을 스캔하거나, OR 조건이 검증기능만 수행하면 변환하지 않음.
- 즉, 분기된 각각의 엑세스가 불필요한 범위를 엑세스하지 않는다고 판단한 경우에만 적용
실행계획
- 'IN-LIST ITERATOR' (IN사용시)나 'CONCATENATION'(OR사용시)으로 실행계획이 나타남
- 강제적인 적용을 위해 'USE_CONCAT' 힌트를 사용
- 함부로 사용하면 엑세스가 불필요하게 분기되어 오히려 처리량이 크게 증가

* 각각이 독립적인 인덱스가 있을경우
SELECT * FROM emp WHERE job='CLERK' OR deptno = 10;
=>
SELECT * FROM emp WHERE deptno = 10
UNION ALL
SELECT * FROM emp WHERE job='CLERK' and deptno<> 10;

3. 서브쿼리를 가진 복잡한 문장을 조인 문장으로 변환   
- 같은 기능의 조인 문장으로 변환하여 최적화 (서브쿼리가 '1' 집합이므로 조인을 해도 메인쿼리에 영향을 주지 않음)

* 서브쿼리의 연결고리가 '1'이 보장되어야 함.
SELECT * FROM emp WHERE deptno IN (SELECT deptno FROM dept WHERE loc='NEW YORK')  
=> SELECT emp.* FROM emp, dept WHERE emp.deptno = dept.deptno AND dept.loc = 'NEW YORK'

- 현재의 문장을 그대로 최적화하는 방법
SELECT * FROM emp WHERE sal > (SELECT AVG(sal) FROM emp WHERE deptno = 20)
 제공자 역할
 - 서브쿼리를 먼저 수행하여 결과를 메인쿼리에 제공
 - 서브쿼리 실행결과를 메인쿼리의 처리주관 인덱스에 제공 할 수 있을 떄 적용
 확인자 역할가
 - 메인쿼리가 실행되면서 서브쿼리를 확인하는 필터링 처리
 - 각의 집합을 엑세스한 후 머지, 혹은 해쉬조인으로 수행

출처 : 새로쓴 대용량 데이터베이스 솔루션 vol.1

Posted by 항아리고미