ORACLE Tip2008. 12. 12. 10:39
--- Problem
사용자는 다음과 같은 상황에서 session 을 kill 하려는 시도를 하게 된다.
1. os 에는 process 가 존재하지 않지만, v$session 에는 active 로 존재하고 있을 경우
2. shadow process 는 살아 있는데, client machine 을 rebooting 한 경우
3. session 이 걸고 있던 lock 을 release 해야 할 경우
4. OS 나 Oracle 의 자원을 지나치게 많이 사용하여 성능을 저하시키는 process
그런데, alter system kill session ('sid, serial#'); 후에 다음과 같은 에러가 발생할 경우가 있다.
 
ORA-00030: User session ID does not exist.
// *Cause:  The user session id no longer exists, probably because the
//          session was logged out.
// *Action: Use a valid session ID.
 
--- 원인과 대책
kill session을 할 수 없는 이유는 PMON이 이미 이 session을 delete하고 있는 중이기 때문이다.
즉, PMON 이 dead session 을 clean-up 하고 있는 중에는 serial number의 값이 증가한다.
문제는 PMON이 process를 kill하는 시간인데, transaction의 크기에 따라, PMON의 rollback 시간이 결정된다.
먼저 PMON은 dead process를 찾아내어, 이 process가 사용한 resource를 release하는 시도를 한다. 
PMON은 계속 이 작업을 시도하다가 마침내, free buffer의 부족으로 더 이상 resource를 free-up 하지 못하게 된다.
이 때, 이 process를 delete하고 있다는 message를 trace file에 출력하는데, 이것은 process를
delete하는 데
필요한 resource(data cache 내의 free buffer)의 부족으로 위의 작업이 지연되고 있다는 의미이다.
PMON이 process 를 clean-up 할 때 걸리는 시간은, 5분에서 24 시간까지 소요 될 수 있다.
문제는 이 process가 hold 하고 있는 lock으로 인해 특정 작업이 수행되지 못하는 데 있다. 
MTS 를 사용할 때는 configuration MTS setting, sqlnet.expire_time 사용)에 따라 다르지만,
clean-up 작업을 하는데 72 시간이 소요된 경우도 있다.
아직까지는 PMON이 작업을 마칠 때까지 기다리는 방법 또는 db를 restartup하는 방법 밖에는 없다.
 
--- PMON 의 작업
PMON은 network failure 나 기타의 원인으로 생긴 old process connection을 clean-up 하는 역할을 한다.
그런데, PMON 은 clean-up 해야 하는 connection 중에 정해진 개수 만큼의 transaction 을 rollback 할 수 있는데,
이 값은 initSID.ora 의 cleanup_rollback_entries(default = 20) 에 의해 결정된다.
예를 들어, 1000 개의 uncommitted update가 있다면, 일정한 시간마다 cleanup_rollback_entries
의 개수 만큼의
record 만 rollback 할 수 있으므로 이 작업 동안에 lock 은 그대로 유지된다.

PMON 은 위의 작업 이외에 DB maintenance 역할이 있으므로, 위의 rollback 이 비교적 빠르게 처리되지 못할 수도 있다.
이러한 rollback을 빠르게 처리하기 위하여 cleanup_rollback_entries 를 늘릴 수도 있다.
그러나, 그 만큼 일정시간 동안 PMON 의 작업이 많아지게 되므로, 다른 사용자들의 작업 요청이 느려지게 되는
trade-off 가 있으므로, 신중히 고려한 후에 수정하는 것이 바람직하다.
alter system kill session 에 의해서도 위와 같이 rollback 이 이루어지는데, 이 session 이 완전히 clean-up 되기
전까지 v$session, v$process에 남아 있게된다.
 
--- ALTER SYSTEM KILL SESSION 을 하기 전에 ...
kill session 을 원할 경우는 다음의 순서대로 작업하는 것이 좋다.
 
1. kill the user process first
2. wait for 3 - 4 minutes
3. query v$session
4. if any information find in v$session, query v$lock
   like
   select count(*) from v$lock where SID ='sid';
 
위의 count(*) 가 0 이 아니라면, 아직 PMON 이 rollback을 끝내지 못한 경우이므로 다시 얼마 후에 v$lock 을 조회하여
lock 의 개수가 감소하였는지 반복적으로 확인한다.
만약, 이 값이 전혀 변하지 않았다면, ALTER SYSTEM KILL SESSION 을 수행하고 v$session,
v$lock을 query 하여
변화가 있는지 확인하여 변화가 있다면, 좀 더 기다린다.
그래도, v$lock 의 count(*) 가 0 이 되지 않을 경우, 마지막으로 수행할 수 있는 유일한 방법은 instance 를 restartup 하는 것이다.
 
Posted by 항아리고미
ORACLE Tip2008. 12. 11. 10:38
-- 테스트 테이블 생성
SQL>CREATE TABLE test_str(
        val varchar2(10));
 
 
-- 테이블에 아래와 같이 특수문자를 인서트 할경우
SQL> INSERT INTO test_str VALUES('Q&A');
a의 값을 입력하십시오:
--
이런 문장이 나옵니다..  
--
특수문자를 갖는 데이터를 인서트 하기 위해서는 다음과 같은 세 가지 해결 방법이 있습니다.

 
▒ 첫번째 방법

   SQL*Plus에서
SET DEFINE OFFSET SCAN OFF를 실행하여
   
Substitution Variable(&)을 Turn Off시킨다.
 
 
   SQL>
SET DEFINE OFF
   SQL>
INSERT INTO test_str VALUES('Q&A');
   1 개의 행이 만들어졌습니다.
   
   SQL>SELECT * FROM test_str;
        VAL
        ------
        Q&A
 

 
▒ 두번째 방법

   SET
DEFINE ON 상태로 유지 시키면서 Substitution Variable을
   다른
Non-Alphanumeric 문자나 Non-White Space 문자(*, % 등등)로 대체시킨다.
 
 
   SQL>
SET DEFINE %
   SQL>
INSERT INTO test_str VALUES('Q&A');
   1 개의 행이 만들어졌습니다.
 

 
▒ 세번째 방법

   SET ESCAPE ON 상태에서(DEFINE은 &로, SCAN은 ON 상태로 유지)
   
특수 문자 앞에 ESCAPE 문자인 BACKSLASH('')를 붙인다.
 
 
   SQL>
SET ESCAPE ON
   SQL>
SHOW ESCAPE
        ESCAPE "" (hex 5c)
   SQL>
INSERT INTO test_str VALUES ('Q&A');
   1 개의 행이 만들어졌습니다.

Posted by 항아리고미
ORACLE Tip2008. 12. 10. 10:36
-- spool 뜰때 라인뒤의 공백을 제거합니다.
SQL>SET TRIMSPOOL ON

 
-- header가 display되지 않고 데이터만 display됩니다.
SQL>SET HEADING OFF           


--  pagesize의 default는 14이며 그대로 하면 14줄마다 1줄씩 공백이  생기므로
-- 그런 현상을 방지하기 위해 크게 지정합니다.
SQL>SET PAGESIZE 1000     


-- linesize도 record 길이만큼 지정하여 아래로 구분되지 않도록 합니다.
SQL>SET LINESIZE  300        


-- 명령이 display되지 않도록 합니다.
SQL>SET ECHO OFF              


-- 조회 결과가 화면에 나오지 않도록 합니다.  
SQL>SET TERM OFF   
Posted by 항아리고미
ORACLE Tip2008. 12. 9. 10:46
1. Toad 9 데이터 그리드에서 한글 깨짐 문제

Toad로 oracle 10g 에서 데이타를 읽어 오는데 DATA 그리드 부분에서 한글이 깨져서 ??? 로 보일 때.


REGEDIT 실행,

아래 경로에 작성하여 주면 된다. 나의 경우 아래 경로에 값이 존재 하지 않아 추가 해주었다.

키이름은 HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE
문자열값
NLS_LANG
값 데이타
KOREAN_KOREA.KO16MSWIN949

작성하고 toad 새로 실행하니 바로 한글이 올바르게 표현 되었다.

HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE 
이 경로에서 정상적으로 동작하지 않을 경우엔 \CLIENT_1 인가?  하위경로에 만들어 주면 된다...


2. Toad 9 버젼에서 엑셀로 저장시 한글 깨짐 문제

  
Toad9 버젼을 사용중 select한 데이터를 엑셀로 보내고자 했는데 한글이 깨질경우
   Save Grid Contents 윈도우의 Write Wide Strings 옵션에 체크를 해주면 된다.

  

  
Posted by 항아리고미
ORACLE Tip2008. 12. 3. 00:56
파일이 저장될 디렉토리 설정하기.


1. sys 나 system user 로 접속한다.

$ sqlplus /nolog
SQL> conn sys/manager
Connected.

2. directory 를 생성한다.
SQL> create directory work_dir as '/work';
Directory created.

3. 생성된 directory 에 대한 read 권한을 준다.
SQL> grant read on directory work_dir to public;
Grant succeeded.

SQL> grant read on directory work_dir to public;
Grant succeeded.

4. 생성한 디렉토리 조회
SQL> select * from dba_directories;


소스보기 프로시져 생성하기


1. 프로시져 소스를 파일로 받는 함수 생성하기.


create or replace procedure cr_proc_script(p_pn varchar2)
is
file_id utl_file.file_type;
cursor c1(v_pn varchar2) is select name, text, line from user_source
where upper(name) like v_pn and type = 'PROCEDURE' order by name,line;
v_name varchar2(30) := ' ';
r_name varchar2(30);
r_text varchar2(4000);
r_line number;
v_line number := 0;

begin

open c1(p_pn);
loop
fetch c1 into r_name, r_text, r_line;
exit when c1%notfound;

if r_name != v_name then

    file_id :=
    utl_file.fopen('WORK_DIR','cr_'||r_name||'.sql', 'w');
    utl_file.put(file_id, 'create or replace ');

    select max(line) into v_line from user_source
    where name = r_name and type = 'PROCEDURE';

end if;

utl_file.put_line(file_id, r_text);
v_name := r_name;

if (r_name = v_name) and (r_line = v_line) then
    utl_file.put_line(file_id, '/');
    utl_file.fclose(file_id);
end if;

end loop;
close c1;

end;
/


2. 프로시져 소스 파일로 받기 사용 방법

- 특정 프로시져 파일로 받기.
SQL> exec cr_proc_script('프로시져명');

- user가 가지고 있는 모든 procedure의 source을 보고자 할때
SQL> exec cr_proc_script('%');


3. Trigger Source 파일로 받는 함수 생성하기.

create or replace procedure cr_trg_script(p_tn varchar2)
is
file_id utl_file.file_type;
cursor c1(v_tn varchar2) is select trigger_name, description, trigger_body
from user_triggers
where upper(trigger_name) like v_tn ;
r_trg_name varchar2(30);
r_description varchar2(2000);
r_trg_body varchar2(32000);

begin

open c1(p_tn);
loop
fetch c1 into r_trg_name, r_description, r_trg_body;
exit when c1%notfound;

file_id :=
utl_file.fopen('/mnt3/rctest80/tool', 'cr_'||r_trg_name||'.sql', 'w');
utl_file.put(file_id, 'create or replace trigger ');

utl_file.put_line(file_id, r_description);
utl_file.put_line(file_id, r_trg_body );

utl_file.put_line(file_id, '/');
utl_file.fclose(file_id);

end loop;
close c1;

end;
/


4. 트리거 소스 파일로 받기 사용 방법

- 특정 트리거 소스 파일로 받기.
SQL> exec cr_trg_script('트리거명');

- user가 가지고 있는 모든 trigger의 source을 보고자 할때
SQL> exec cr_trg_script('%');

Posted by 항아리고미
ORACLE Tip2008. 11. 25. 09:38

아래와 같이 partition table을 생성한다.

SQL> create table part_tbl (
in_date number primary key ,
empno number,
ename varchar2(20),
job varchar2(20)
         )
        partition by range (in_date) (
partition part_tbl_03 values less than (20000331) tablespace pts_03,
partition part_tbl_04 values less than (20000430) tablespace pts_04,
partition part_tbl_05 values less than (20000531) tablespace pts_05,
partition part_tbl_06 values less than (20000630) tablespace pts_06,
partition part_tbl_07 values less than (20000731) tablespace pts_07,
partition part_tbl_08 values less than (20000831) tablespace pts_08,
partition part_tbl_09 values less than (20000930) tablespace pts_09,
partition part_tbl_10 values less than (20001031) tablespace pts_10
        );

1. partition 을 add하는 방법

11월과 12월에 대해 partition을 add하고 싶은 경우 다음과 같이 할 수 있다.

SQL> alter table part_tbl add partition part_tbl_11
values less than (20001130) tablespace pts_11;

SQL> alter table part_tbl add partition part_tbl_12
values less than (20001231) tablespace pts_12;

2. 특정 partition 을 삭제하는 방법

8월에 해당하는 partition을 없애고 싶은 경우는 다음과 같이 실행한다.

SQL> alter table part_tbl drop partition part_tbl_08;

drop된 후에 새로 8월에 해당하는 데이타가 입력되면
9월의 partition이 less then (20000930) 으로 되어 있으므로
9월에 해당하는 partition에 저장된다.

3. partition을 나누는 방법

1월, 2월에 해당하는 partition을 생성하려면 partition을
add하는 것으로는 불가능하고 기존의 partition에서 split 해야 한다.

SQL> alter table part_tbl split partition part_tbl_03
at (20000229)
into (partition part_tbl_02 tablespace pts_02,
partition part_tbl_03_1 tablespace pts_03);

위와 같이 하면 기존의 partition에서 2월29일을 기준으로 2월과 3월로
partition이 나눈다. 그리고 나서 다시 split 해야한다.

SQL> alter table part_tbl split partition part_tbl_02
at (20000131)
into (partition part_tbl_01 tablespace pts_01,
partition part_tbl_02_1 tablespace pts_02);

4. partition name을 변경하는 방법

partition name 을 바꾸고 싶다면 다음과 같이 실행한다.

SQL> alter table part_tbl rename partition part_tbl_02_1 to part_tbl_02;
SQL> alter table part_tbl rename partition part_tbl_03_1 to part_tbl_03;

5. partition의 tablespace를 옮기는 방법

partition part_tbl_10을 저장하는 tablespace를 pts_10 에서 pts_10_1로
바꾸고 싶은 경우 아래와 같은 command를 사용한다.

SQL> alter table part_tbl move partition part_tbl_10
tablespace pts_10_1 nologging;

6. 특정 partition의 data를 truncate하는 방법

partition의 data를 모두 삭제하려면 truncate하는 방법을 사용할 수가
있는 데, truncate는 rollback 이 불가능하며 특정 partition 전체를
삭제하므로 주의하여 사용하여야 한다.

SQL> alter table part_tbl truncate partition part_tbl_02;

7. Partition table의 물리적인 속성 변경

partition table은 특정 partition의 속성만 변경할 수 있고,
table의 속성을 변경하여 전체 partition에 대해 동일한 변경을 할 수 있다.

SQL> alter table part_tbl storage( next 10M);
-> part_tbl 의 모든 partition의 next 값이 변경된다.

SQL> alter table part_tbl modify partition part_tbl_05
storage ( maxextents 1000 );
-> part_tbl_05 partition의 maxextents 값만 변경한다.

8. Index의 관리

위와 같이 partition table 관련 작업을 한 후에는 table에 걸려 있는
local(partitioned) index 나 global index를 반드시 rebuild해 주어야 한다.

특정 partition의 index를 rebuild 하려면

SQL> alter index ind_part_tbl rebuild partition i_part_tbl_02;

그리고 global index를 rebuild하려면

SQL> alter index part_tbl_pk rebuild;

출처 : OTN Forums

Posted by 항아리고미
ORACLE Tip2008. 11. 19. 14:48


현재 돌고있는 SQL이 언제 끝나는지 예측할 수 있다.

v$session_longops view를 통해 알수 있는데 이 view가 보이지 않으면
DBMS_APPLICATION_INFO package의 SET_SESSION_LOGOPS procedure를 돌리면 된다.

Oracle 8.0 부터 제공되고 있는 v$session_longops 는 단일 long running operation에 대한 진행 상태를 operatoin별로 제공해 주는 view로 DSS, DW와 같은 long running job이 많은 system에서는 유용한 정보를 확인할 수 있는 table이다.

* 이 dynamic view에서 다루어지는 operation들에는 다음의 것들이 있다.
- Archiving
- Rman Backup and Restore
- Parallel Query
- Recovery ( Crash and Media )
- Full Table scans (10000 blocks 이상의 full table scan을 long operation으로 간주한다.)
- Sorting
- Analyze using DBMS_STATS Not seen yet
- Hash Cluster Creation
- Hash Joins Phase 2

* v$session_longops COLUMNS
- SID : Session identifier
- SERIAL# : Session serial number
- OPNAME : The operation name
- TARGET : The object on which the operation is carried out
- TARGET_DESC : Description of the target
- SOFAR : The units of work done so far
- TOTALWORK : The total units of work
- UNITS : The units of measurement
- START_TIME : The starting time of operation
- LAST_UPDATE_TIME : Time when statistics last updated
- ELAPSED_SECONDS : The number of elapsed seconds from the start of operations
- CONTEXT : Context
- MESSAGE : Statistics summary message

사용예 >
select *
from v$session_longops;

-- 특정 유저가 사용한 작업만을 보고자 할때.
select *
from v$session_longops
where (sid, serial#) in (select sid, serial# from v$session  where username = 'SCOTT');

-- 시작시간과 현재의 진행상태를 보고자 할때.
select sid, serial#, opname, to_char(start_time,'HH24:MI:SS') as START_TIME, (sofar/totalwork)*100 as percent_complete
from v$session_longops

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 항아리고미
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 항아리고미
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 항아리고미