오라클 운영시 특정 세션이나 프로세스가 resource를 과도하게 소모하거나, 속도 저하 등의 이상이 발생해 다른 세션들 까지 영향을 주는 경우가 종종 발생하곤합니다. 이럴 때 해당 세션이나 프로세스의 문제를 해결하기 위해 시간을 끌다가는 전체 업무에 주는 영향으로 인해 더 큰 문제가 발생할 수 있죠.

다음은 개별 세션이나 프로세스가 이상이 있을때 가징 기본적으로 수집해야 하는 trace/dump를 수행하는 방법입니다. 알아서 관련 정보를 다 수집해 주면 좋겠으나, 일일히 관련 정보를 수집해야 하니 좀 번거로울 수 있겠으나, 이런 작업들을 안해 놓으면 문제가 미궁으로 빠질 수 있으므로, 미리미리 알아 놓는 게 좋겠죠..

오라클은 많은 trace/dump 수행 방법을 제공하고 있는데, 다음의 event 10046, errorstack은 개별 세션의 정보를 수집합니다. 물론 이 두개의 trace/dump를 수행하고 전체적인 systemstate dump나 hanganalyze도 같이 수행을 하면 전체적인 영향까지도 확인 할 수 있겠죠.

10046 event는 일반적인 SQL_TRACE 기능을 수행합니다. 또 특정 level을 지정해주면 해당 세션의 wait event와 bind value까지 tracing 해줍니다.

1  - Enable standard SQL_TRACE functionality (Default)
4  - As Level 1 PLUS trace bind values
8  - As Level 1 PLUS trace waits
12 - As Level 1 PLUS both trace bind values and waits

ERRORSTACK dump은 해당 process의 현재 상태 및 정보를 수집합니다. SQL 구문과 Call stack, errorstack, processstate, context area 정보를 수집합니다.

0    Error stack only (no longer be a valid option)
1    Error stack and function call stack (if implemented)
2    As 1 plus the ProcessState
3    As 2 plus the context area (all cursors and current cursor highlighted)

다음은 oradebug를 이용해 10046 event를 on/off 시키는 방법입니다.
event를 on 시킨 후 충분한 데이터를 수집했다고 판단되면 off 시키면 되며, 결과물은 sql_trace 처럼 tkprof로 정리해서 볼수 있다.

* 10046 tracing on
sqlplus '/as sysdba'
oradebug에 세션이나 프로세스를 지정할 때 oracle pid나 o/s pid, 자기자신의 process를 지정할 수 있다.
따라서 위의 3가지 중 하나를 지정하면 된다.
SQL>oradebug setorapid [Oracle process id]
SQL>oradebug setospid [O/S process id]
SQL>oradebug setmypid
trace 발생양에 대한 제한을 unlimit로 지정한다.
SQL>oradebug unlimit
event 10046을 level 12로 지정한다.
SQL>oradebug Event 10046 trace name context forever, level 12
생성한 trace file이름을 출력한다.
SQL>oradebug tracefile_name
SQL>exit

* 10046 trace off
sqlplus '/as sysdba'
10046 trace 지정시 사용한 oracle pid나 o/s pid, 자기자신의 process를 지정 한다.
SQL>oradebug setorapid [Oracle process id]
SQL>oradebug setospid [O/S process id]
SQL>oradebug setmypid
event 10046 설정을 해지한다.
SQL>oradebug Event 10046 trace name context off
SQL>exit

다음은 oradebug를 이용해 ERRORSTACK dump를 수행하는 방법입니다. ERRORSTACK은 해당 시점의 프로세스 정보를 수집하는 것이므로 on/off 단계는 필요 없이 한번만 수행해 주면 됩니다.

* ERRORSTACK dump
sqlplus '/as sysdba'
oradebug에 세션이나 프로세스를 지정할 때 oracle pid나 o/s pid, 자기자신의 process를 지정할 수 있다.
따라서 위의 3가지 중 하나를 지정하면 된다.
SQL>oradebug setorapid [Oracle process id]
SQL>oradebug setospid [O/S process id]
SQL>oradebug setmypid
trace 발생양에 대한 제한을 unlimit로 지정한다.
SQL>oradebug unlimit
errorstack dump를 level 3으로 수행한다.
SQL>oradebug dump errorstack 3
생성한 trace file이름을 출력한다.
SQL>oradebug tracefile_name
SQL>exit

가끔 sqlplus 자체가 수행이 되지 않아 trace/dump 수행이 어려운 경우가 있는데, 이러한 경우 sqlplus의 -prelim option을 사용하거나 debugger tool인 dbx를 사용해서 errorstack을 수행할 수 있습니다.

dbx debugger를 이용한 process의 call stack 보기.

dbx -a $pid
dbx) where
dbx) detach
 
* 반드시 detach 하지 않을 경우 attach 한 프로세스는 비정상 종료된다.
* -a flag는 해당 프로세스에 attach 하여 dbx 시행하는 동안 해당 프로세스는 실행이 중지되므로 background process에 대한 attach는 피하는 편이 신상에 좋습니다.. --;

dbx debugger를 이용한 core file의 call stack 보기.

dbx program명 core
dbx) where
dbx) quit


위의 내용은 oracle metalink note에서 참고했습니다.
Note.21154.1 EVENT: 10046 "enable SQL statement tracing (including binds/waits)"
Note.37871.1 EVENT: ERRORSTACK - How to get
Note 1058210.6 How to enable 10046 for another session using ORADEBUG  
Note 62294.1 The DBMS_SUPPORT Package                                
Note 35054.1 Interpreting ERRORSTACK output                          
Note 39817.1 Interpreting RAW 10046 output                           




'Oracle Database' 카테고리의 다른 글

Oracle AWR 자료 query 할때 편한 함수 LAG  (2) 2009.09.03
oracle TimesTen 11g Conference  (0) 2009.09.03
oracle - recovery manager (RMAN)  (0) 2009.08.23
Oracle OTN Developer Day  (0) 2009.08.20
Oracle Execution Plan 관련 view 들  (0) 2009.08.18

오라클에서 수행되는 cursor의 수행 정보와 이와 관련된 각종 statistic 정보를 확인할 수 있는 view가 몇개 있습니다.
다음은 해당 view에 대한 비교와 column 정보들, 그리고 해당 view를 이용한 몇개의 sql script 들입니다.


V$SQL_PLAN_STATISTICS:
각 operation에 대한 execution statistics 정보를 제공한다.

1)EXECUTIONS:
Child cursor의 수행된 횟수 이다. 따라서 동일한 SQL이더라도 optimizer 환경이나 bind variable size 등의 변경에 의해 다른 child cursor를 가질 수 있으므로 이에 대한 고려도 필요하다.
두개의 세션에서 동일한 SQL을 2회 수행하는 경우나, 같은 세션에서 동일한 SQL을 2회 수행한 경우 동일하게 2의 값을 갖는다.

2)LAST_OUTPUT_ROWS and OUTPUT_ROWS:
LAST_OUTPUT_ROWS는 해당 operation에 의해 마지막에 처리된 실제 row 수 이며, OUTPUT_ROWS는 누적 합이다.

3)LAST_DISK_READS and DISK_READS:
LAST_DISK_READS는 해당 operation이 disk를 읽은 횟수를 의미하며, DISK_READS는 누적 합이다.

V$SQL_PLAN_STATISTICS_ALL:

다음의 관련 view의 데이터에 대한 전체적인 정보를 갖는다.
V$SQL_PLAN                   (all operations, objects, cost, cardinality etc)
V$SQL_PLAN_STATISTICS (execution statistics as above)
V$SQL_WORKAREA           (memory usage)

1) estimated_optimal_size
해당 operation을 메모리상에서 처리하기 위해 측정된 memory size (KB)

2) last_memory_used
cursor의 마지막 execution 동안 사용된 memory (KB)

3) active_time
Average active time (in centi-seconds)

다음의 SQL script는 특정 SQL cursor에 대한 plan과 관련 statistic 정보를 보여줍니다.

qeps.sql과 qep.sql을 생성해 수행하면 SQL의 성능을 평가하는 8개의 항목에 대해 지정된 갯수의 SQL과 그에 따른 statistic 정보를 보여줍니다. init parameter인 statistics_level를 ALL로 설정해야 정상적인 결과를 보여줍니다.

참고 :
Note 186548.1 9i Release 2 Cached cursors information in the row source level
Note 260942.1 Display Execution plans from Statement's in V$SQL_PLAN
Note 550578.1 How to Obtain the most Resource Intensive SQL Execution Plans using the Libr...





AWR table map을 찾던 중 "A Tour of the AWR Tables"라는 NOCOUG Summer Conference에서 소개된 자료를 확인할 수 있었습니다. 제목을 보니 AWR관련 table에 대한 여러 힌트를 얻을 수 있을 듯해서 자료를 보니 "load spike"를 찾기 위한 좀 다른 방법을 설명하고 있네요.

이전 " oracle awr 설정 시 고려해야 할 점" post에서 강호동, 이건희 회장까지 등장시키며 AWR 자료 수집 주기를 15 ~20분으로 줄여야한다고 글을 썼는데, 이 글의 저자는 "In my experience, the hourly interval is appropriate." 라고 하더군요. 저자는 DBA_HIST_SYSSTAT의 DB time, elapsed time 등의 load profile 자료를 사용하지 않고 1초마다 수집되는 ASH의 자료를 이용해 "load spike"를 찾는 방법을 제시하고 있습니다.

오옷 .. 그런 방법이.. 근데, 그 외의 성능관련 정보는 어떻게... --;
추가적인 AWR 관련 table을 이용한 문제가 될만한 SQL 찾는 방법 등도 같이 소개합니다.

Average Active Session이 튀는 시간 찾기.
column sample_hour format a16

select
   to_char(round(sub1.sample_time, 'HH24'), 'YYYY-MM-DD HH24:MI') as sample_hour,
   round(avg(sub1.on_cpu),1) as cpu_avg,
   round(avg(sub1.waiting),1) as wait_avg,
   round(avg(sub1.active_sessions),1) as act_avg,
   round( (variance(sub1.active_sessions)/avg(sub1.active_sessions)),1) as act_var_mean
from
   ( -- sub1: one row per second, the resolution of SAMPLE_TIME
     select
        sample_id,
        sample_time,
        sum(decode(session_state, 'ON CPU', 1, 0))  as on_cpu,
        sum(decode(session_state, 'WAITING', 1, 0)) as waiting,
        count(*) as active_sessions
     from
        dba_hist_active_sess_history
     where
        sample_time > sysdate - (&hours/24)
     group by
        sample_id,
        sample_time
   ) sub1
group by
   round(sub1.sample_time, 'HH24')
order by
   round(sub1.sample_time, 'HH24')
;

SAMPLE_HOUR          CPU_AVG   WAIT_AVG    ACT_AVG ACT_VAR_MEAN
----------------- ---------- ---------- ---------- ------------
2008-04-16 07:00         1.4         .4        1.8           .6
2008-04-16 08:00         1.8         .5        2.3            1
2008-04-16 09:00         2.3         .5        2.8          1.3
2008-04-16 10:00         2.6         .6        3.2          2.3
2008-04-16 11:00         3.5         .6        4.1          2.3
2008-04-16 12:00         2.4         .6          3          1.1
2008-04-16 13:00         2.3         .6        2.9            1
2008-04-16 14:00         3.7        2.7        6.4         95.4   <== spike in variance
2008-04-16 15:00         3.1         .7        3.8          1.9
2008-04-16 16:00         2.9         .7        3.6          1.6
2008-04-16 17:00         2.3         .4        2.7           .9
2008-04-16 18:00         2.1         .6        2.7          2.6

Average Active Session이 튀는 시간대의 특정 분단위 찾기.
column sample_minute format a16

select
   to_char(round(sub1.sample_time, 'MI'), 'YYYY-MM-DD HH24:MI') as sample_minute,
   round(avg(sub1.on_cpu),1) as cpu_avg,
   round(avg(sub1.waiting),1) as wait_avg,
   round(avg(sub1.active_sessions),1) as act_avg,
   round( (variance(sub1.active_sessions)/avg(sub1.active_sessions)),1) as act_var_mean
from
   ( -- sub1: one row per second, the resolution of SAMPLE_TIME
     select
        sample_id,
        sample_time,
        sum(decode(session_state, 'ON CPU', 1, 0))  as on_cpu,
        sum(decode(session_state, 'WAITING', 1, 0)) as waiting,
        count(*) as active_sessions
     from
        v$active_session_history
     where
        sample_time > sysdate - (&minutes/1440)
     group by
        sample_id,
        sample_time
   ) sub1
group by
   round(sub1.sample_time, 'MI')
order by
   round(sub1.sample_time, 'MI')
;

SAMPLE_MINUTE           CPU_AVG   WAIT_AVG    ACT_AVG ACT_VAR_MEAN
-------------------- ---------- ---------- ---------- ------------
2008-04-16 13:54:00           3          1          4            0
2008-04-16 13:55:00         3.2         .3        3.5           .7
2008-04-16 13:56:00         4.2         .3        4.5          3.4
2008-04-16 13:57:00         3.8         .8        4.7           .7
2008-04-16 13:58:00         6.3          1        7.3          1.6
2008-04-16 13:59:00         3.4         .4        3.8           .2
2008-04-16 14:00:00         8.3         .5        8.8          1.8
2008-04-16 14:01:00        10.7        2.2       12.8           .5
2008-04-16 14:02:00         3.5         .7        4.2           .5
2008-04-16 14:03:00         2.6        1.2        3.8          1.5
2008-04-16 14:04:00         3.3        1.2        4.5          1.3
2008-04-16 14:05:00         8.2         .7        8.8          2.1
2008-04-16 14:06:00         6.7        1.3          8          1.1
2008-04-16 14:07:00         4.7        3.2        7.8          3.7
2008-04-16 14:08:00        20.5      109.8      130.3          170  <== spike in AAS
2008-04-16 14:09:00           6        1.3        7.3         10.3
2008-04-16 14:10:00         2.6         .4          3           .8
2008-04-16 14:11:00           4         .3        4.3          1.1
2008-04-16 14:12:00         5.7         .8        6.5          1.6
2008-04-16 14:13:00           3         .3        3.3           .7
2008-04-16 14:14:00         1.8         .7        2.5           .6
2008-04-16 14:15:00         3.3          2        5.3          2.2


 


다음의 그림은 AWR 내의 wait event관련 view의 primary/reference key 들입니다.
필요한 view를 각각의색에 맞게 join하여 사용할 수 있습니다.


다음은 Oracle 10g R2 Reference 메뉴얼 링크입니다.
해당 view가 어떤 정보들을 가지고 있는지 확인할 수 있습니다.

DBA_HIST_SERVICE_WAIT_CLASS
DBA_HIST_SESS_TIME_STATS
DBA_HIST_SYSTEM_EVENT
DBA_HIST_ACTIVE_SESS_HISTORY
DBA_HIST_BASELINE
DBA_HIST_BG_EVENT_SUMMARY
DBA_HIST_WAITCLASSMET_HISTORY
DBA_HIST_WAITSTAT
DBA_HIST_EVENT_NAME
DBA_HIST_SNAPSHOT







Oracle AWR 관련 table 중 SQL에 관련된 table 들과 reference key를 그린 그림입니다.
다음의 table join으로 과거의 SQL 수행 정보 등을 찾을 수 있습니다. 


아래의 SQL은 Oracle Note에 나온 AWR 수집 데이터에서 SQL 관련 정보를 추출하는 SQL 입니다.

SQL ordered by CPU time:

column sqltext format a65
set pages 60
set lines 132
set trims on

select x.*, dbms_lob.substr(d.sql_text) sqltext
from (
select distinct sql.dbid, sql.sql_id, sum(sql.cpu_time_total)
cpu_total
from dba_hist_sqlstat sql
where sql.snap_id between &begin_id and &end_id
group by
sql.dbid, sql.sql_id
order by
sum(sql.cpu_time_total) desc
) x,
dba_hist_sqltext d
where d.sql_id = x.sql_id
and d.dbid = x.dbid
and rownum <= 10;

SQL ordered by Executions:

column sqltext format a30
select distinct sql.sql_id, dbms_lob.substr(d.sql_text) sqltext, sum(sql.executions_total) from
dba_hist_sqlstat sql,
dba_hist_snapshot s,
dba_hist_sqltext d
where
s.snap_id between &begin_id and &end_id
and rownum <= 10
group by sql.sql_id, dbms_lob.substr(d.sql_text)

SQL ordered by Disk Reads:

column sqltext format a30
select distinct sql.sql_id, dbms_lob.substr(d.sql_text) sqltext, sum(sql.
disk_reads_total) from
dba_hist_sqlstat sql,
dba_hist_snapshot s,
dba_hist_sqltext d
where
s.snap_id between &begin_id and &end_id
and rownum <= 10
group by sql.sql_id, dbms_lob.substr(d.sql_text)


참고 : Note 833323.1 Customized queries from AWR

 
100명의 사람들이 있습니다.
이 사람들의 어떤 평균 수치값이 주어져 있습니다.

이 그룹에 주어진 평균 수치가 만약 몸무게나 키, 허리 둘레 등에 대한 평균이라고 한다면,
이 그룹 중 강호동처럼 (몸무게가 어떤지는 잘은 모릅니다^^;) 몸무게가 다른 사람들 보다 많이 나가는 사람을 찾을 수 있을가요? 

물론 평균 수치가 재산, 보유주택 가격 등에 대한 평균이고 이 중 이건희 회장 같은 사람이 있다면 당연히 그 평균값은 거의 한 사람의 값과 같겠죠. 따라서 일반적이지 않은 사람이 섞여있다고 판단할 수 있습니다.

(이 내용은 [블랙스완]이란 책에서 경제학자들의 일반화 오류에 대한 예입니다. 물론 거긴 강호동이나 이건희 회장은 나오지 않습니다만...ㅋㅋ)

database system 내에서 수행되는 많은 AP들이 있습니다.
AWR은 현황에 대한 분석 뿐 아니라 많은 경우 비 정상적으로 문제를 발생하는 AP 등을 찾는데도 자주 사용됩니다.
대부분의 비정상적인 AP는 일반 AP에 비해 2~3배 정도의 resource를 더 많이 사용하죠.

위의 예처럼 대부분의 수치를 차지하는 이건희 회장 같은 AP가 있다면, 이건 계발에 대한 검증이나 운영장비로의 적용 단계에 문제가 있다고 판단해야 합니다 !! 또 AWR을 보지 않아도 찾아내기 쉽죠.
(개인적으로 이건희 회장을 좋아하진 않지만, 뭐 다른 의도가 있는건 아닙니다. 얼마전 뉴스에서 제일 돈이 많다고해서 부럽기도 하고.. 뭐)

서론이 너무 길었지만,
특정 시간대에 문제의 소지가 있는 AP가 있는지에 대한 판단은 그 표본 범위가 작을 수록 더 쉬워지기 마련입니다.
즉 강호동이 10000명 중 하나일 경우와 10명 중 하나일 경우 전체 평균에 기여하는 부분이 달라지죠.

oracle 10g 부터 AWR이 default로 수행됩니다. 1주일의 보관 주기와 1시간의 수집 주기를 가지고 있죠.
하지만 대부분의 제가 본 AWR 주기는 (얼마 보진 않았지만.. --;) default로 설정되어 사용하고 있습니다.

만약 특정 시간동안 hang이 발생했거나 resource contention이 발생했다면 이에 대한 증거들인 database statistic 값들이 1시간이란 시간 안에서 "나 여기 있어요" 하고 말할 수 있을까요?

AWR의 데이터를 한달에 한번씩 수집해서 "이번달엔 이 정도 일했습니다."라고 말할 용도가 아니라면
적어도 15분 ~ 30분 정도의 수집 주기와 AP 수행 주기의 2배 만큼은 보관해야 합니다.
 
또 한가지 AWR에는 base-line을 기록할 수 있습니다.
base-line은 말 그대로 기준선이 됩니다. 이 base-line을 사용하면 "막연히 이번달엔 지난달 보다 좀 느려진것 같아요" 대신 "이번달은 지난달 보다 load가 1.5배 정도 더 발생해 전체적인 속도가 늦어졌어요" 라고 말할 수 있겠죠...

다 쓰고 보니 별 내용이 없군요..
하지만 위의 예제는 꼭 써먹구 싶었습니다... ㅋㅋㅋ

* 현재 AWR 설정 값 확인

select snap_interval, retention from dba_hist_wr_control;

SNAP_INTERVAL       RETENTION
------------------- -------------------
+00000 01:00:00.0   +00007 00:00:00.0

* AWR 설정값 변경

begin
   dbms_workload_repository.modify_snapshot_settings (
      interval => 20,
      retention => 2*24*60
   );
end;

* Base-line 설정

exec dbms_workload_repository.create_baseline (56,59,'apply_interest_1'):

* Base-line 확인

select * from dba_hist_baseline;

      DBID BASELINE_ID BASELINE_NAME        START_SNAP_ID END_SNAP_ID
---------- ----------- -------------------- ------------- -----------
4133493568           1 apply_interest_1                56          59





인트라 파티션 병렬 기능(intra-partition parallelism)

병렬 실행의 동적 로드 밸런싱 기능의 이점을 활용
내부에서 모두 자동으로 처리
많은 데이타 스큐가 있을 경우 그 진가가 최대한 발휘

Oracle8i의 경우 하나의 테이블 파티션은 병렬 삽입(PDML) 중 오직 하나의 슬래이브 만을 따른다. 이에 따라 파티 션 간의 데이타 스큐가 발생할 경우, 로드 밸런싱은 불가능하게 된다. 예를 들어 여러 애플리케이션에서 테이블은 날 짜 열 범위에 의해 파티셔닝되며 행은 주로 마지막 파티션에 삽입되다고 할 경우를 마지막 파티션에서 운영되는 슬래 이브는 다른 슬래이브에 비해 훨씬 많은 작업을 해야 한다.

Oracle9i는 인트라 파티션 병렬 기능(intra-partition parallelism)을 채용했다.

여러 슬래이브가 하나의 파티션에서 작업하도록 지원할 경우 성능 병목을 완화하는데 도움이 된다.
이는 병렬 실행의 동적 로드 밸런싱 기능의 이점을 활용하는 것이다. 이는 PDML이 지원될 경우 내부에 서 모두 자동으로 처리된다.

인서트 인트라 파티션 병렬 기능(intra-partition parallelism of Inserts)의 이점은 많은 데이타 스큐가 있을 경우 그 진가가 최대한 발휘된다. 삽입된 데이타가 균일할 경우 일반 병렬 삽입에 비해 이점이 거의 없거나 전혀 없다.

샘플 문제:
Operational Data Store 테이블 SALES_ODS의 행이 월별로 분할되는 fact 테이블 SALES_1999 에 삽입되어야 한다. 데이타 배포는 스큐가 되며 아래와 같은 그래프로 나타난다.


구현:
Oracle8i와 Oracle9i, 모두에서 이는 다음과 같이 구현된다.

ALTER SESSION ENABLE PARALLEL DML;

INSERT INTO SALES_1999 /*+ parallel(SALES_1999, 10) */ SELECT * from SALES_ODS;

다음 표는 증가하는 데이타 양에 따른 병렬 삽입의 경과 시간을 비교한 것이다.




데이타 스큐를 증가시켜 1999년 11월에 거의 스파이크에 도달하게 된다면 이보다 더 큰 성능 이점을 기대할 수 있다. Oracle8i의 병렬 삽입의 성능은 스큐의 증가에 따라 저하되지만 Oracle9i를 이용할 경우 그 성능은 일정하 다. 다음 결과는 보다 많은 스큐가 적용된 데이타 분배에 대한 것이다(아래의 배포 그래프 참조).




Oracle9i에서 인서트 인트라 파티션 병렬 기능(intra-partition parallelism of Inserts)은 다음과 같은 이점을 통해 Oracle8i Parallel Insert(PDML) 보다 나은 성능을 발휘할 수 있다.

1. CPU 활용도 확대 - Oracle9i의 경우 이 작업은 Oracle8i와는 달리 거의 전적으로 CPU에 의존한다
2. 보다 효과적인 IO 대역폭 활용 - Oracle9i의 경우 Oracle8i 보다 높은 tps(transaction per second)를 제공한다
3. 다 높은 IO 처리 성능 - Oracle9i의 경우 Oracle8i보다 더 높은 IO 전송 처리 성능을 제공한다


이 POST는 "오라클 기술백서 : Oracle 9i와 DSS 환경에서의 성능과 확장성"의 일부 내용을 발췌한 것입니다.



'Oracle Database' 카테고리의 다른 글

oracle awr 설정 시 고려해야 할 점  (0) 2009.08.11
Oracle Enqueue 개요  (0) 2009.08.11
INTRODUCTION TO PARALLEL DML  (0) 2009.07.17
Oracle Parallel Query Execution  (1) 2009.07.16
Oracle 10G Transaction Rollback Monitoring  (0) 2009.07.14

Parallel DML은 대량의 table/index에 대해 "speed up"과 "scale up"을 위해 insert, update, delete ,merge operation에 parallel execution mechanism을 적용시킨 operation을 말합니다. 즉 일반적으로 말하는 parallel query나 parallel direct-path read 등은 포함되지 않는 개념입니다.

'ParallelExecution'에 해당되는 글 4건

  1. 2009/07/17 삽입을 위한 인트라 파티션 병렬 기능(intra-partition parallelism)
  2. 2009/07/16 Parallel Query Execution
  3. 2009/07/07 10.2 oracle concept - 19 Direct-Path INSERT

Parallel DML은 기본적으로 session에 "enable" 되어 있지 않습니다. PDML과 serial DML의 locking, transaction, disk space requirement 등의 차이에 의해 PDML mode의 "enable"이 요구됩니다.

ALTER SESSION ENABLE PARALLEL DML;

따라서 Parallel DML이 "disable"되있을 경우 parallel hint나 table/index에 degree가 설정되어 있어도 이는 무시되게 됩니다. 물론 PDML mode가 "enable"되어 있어도 parallel hint나 table/index에 대한 degree가 설정되어 있어야 PDML로 수행 가능하다.


한 Transaction은 서로 다른 table에 대해 여러 PDML이 수행될 수 있습니다. 그러나 PDML로 변경된 table에 대해 해당 transaction 내에서 serial/parallel 명령(DML or Query)으로 access를 할 수 없습니다. 즉 commit/rollback 등으로 transaction을 완료 후에야 동일 table에 대한 operation이 가능합니다.
(참조 Note 201978.1 PDML Restrictions on Parallel DML)


Oracle 9i 이후에 intra-partition parallelism 개념이 소개되었습니다.
이 개념은 partition당 한개씩만 수행되는 parallel execution server의 제한을 완화(?) 시키는 개념입니다.
(참고 Note 241376.1 What is Intra-partition parallelism )

특정 세션의 PDML의 "enable" 여부는 v$session의 PDML_STATUS, PDDL_STATUS, PQ_STATUS column으로 확인 할 수 있습니다.

SQL> SELECT SID,PDML_STATUS, PDDL_STATUS, PQ_STATUS FROM V$SESSION;

SID PDML_STATUS PDDL_STATUS PQ_STATUS
---------- ------------ ------------ ------------
141 DISABLED DISABLED DISABLED
143 DISABLED ENABLED ENABLED
145 DISABLED ENABLED ENABLED
148 DISABLED ENABLED ENABLED
150 DISABLED DISABLED DISABLED


이 POST는 metalink note를 참고하여 작성되었습니다.
Note 201457.1- Introduction to PDML





정리:
1. slave 가 disk로 부터 데이터를 읽을 때 buffer cache를 거치지 않는 direct I/O path read를 수행하는데, 작업전 slave는 이미 변경되었으나 disk에 반영되지 않은 데이터를 buffer cache에서 disk로 강제로 flush 한다. 그후 data를 direct path I/O로 읽는다.

2. slave는 consumer slave와 producer slave로 나눌 수 있는데, consumer slave는 추가적인 작업이 필요할 때 수행되며, 이로 인해 예상한 slave 개수보다 더 많은 slave가 작업을 수행할 수 있다.

3. 기본적으로 optimizer가 query를 parallel로 수행하도록 SQL 수행 계획을 생성되더라도 수행시 요구되는 parallel slave를 띄우기 위한 충분한 resource가 없을 경우, 사용자에게 특별한 메세지 없이 serial하게 query를 수행한다. 이러한 경우가 발생하면 query 수행시간이 예상보다 더 늦어지는 일이 발생할 수 있다.

4. serial query가 parallel query보다 더 유리한 경우는 index에 의해 query 조건의 선처리로 대상 데이터량을 줄이는데서 발생한다.


1. Introduction to Parallel Execution

대용량 table에 대한 Full table scan이나 큰 size의 index 생성 등 많은 데이터를 handle할 때 작업들은 여러 process에게 나누어 수행하도록 할 수 있습니다.

이러한 작업 방식을 parallel execution 또는 parallel processing라고 합니다. 

parallel execution은 여러가지 유형의 작업에서 쓸만합니다. 

  • large table scan이나 join 또는 partitioned index scan등의 query 
  • large table이나 index 생성 
  • Bulk insert나 update, delete
  • Aggregations 


2. How Parallel Execution works


(1) 처음 query가 oracle server로 들어오면 query를 분석하는 parse 단계를 거치게 됩니다. 이때 여러개의 access path 중 가장 성능이 좋다고 판단되는 access path가 결정되게 됩니다. parallel execution이 선택되게 되면, 

(2) 수행 단계에서 query를 수행한 user shadow process는 query coordinator(QC)가 되고 parallel slave 들이 요청한 session에 할당됩니다.

(3) query coordinator는 할당된 slave process에 ROWID나 partition 단위로 데이터를 나눠줍니다.

(4) "producer slave"는 데이터를 읽어 "table queue"로 데이터를 보내는데, "consumer slave"나 query coordinator가 데이터 처리를 위해 이 table queue의 데이터를 대기하게 됩니다.

 (5) 만약 sort가 필요한 parallel execution이라면 이들 table queue의 데이터는 "consumer slave process"에 의해 읽혀져 sort 되며,sort 된 데이터는  새로운 "table queue"에 보내지게 됩니다. 이들 sort 된 데이터는 다시 Query coordinator에 의해 읽혀집니다.

만약 sort가 필요 없는 parallel execution이라면 producer slave가 보낸 table queue데이터를 query coordinator가 직접 읽어 처리합니다.

[그림] parallel executions with/without SORT



용어 설명 :

* Query Coordinator(QC)

parallel execution을 수행한 foreground process, 즉 query를 수행한 session으로 query slave로 부터 데이터를 받게 된다. 

* Slaves

slave는 disk로 부터 바로 데이터를 읽거나 다른 slave에 의해 만들어진 table queue 구조로 부터 읽어 그것을 자신의 queue에 write한다.  slave 가 disk로 부터 데이터를 읽을 때 buffer cache를 거치지 않는 direct I/O path read를 수행한다. slave는 이미 변경되었으나 disk에 반영되지 않은 데이터를 buffer cache에서 disk로 강제로 flush 한다. 그후 data를 direct path I/O로 읽는다. 

 slave는 producers slave와 consumer slave의 두개의 종류가 있다. 

 Producers slave는 QC로 부터의 주어진 ROWID range나 partition을 통해 data block을 읽어 관련 데이터를 읽어 온다. 이 데이터는 table queue에 보내지며 이를 다시 QC나 consumer slave가 처리하게 된다.

Consumer slave는 producer slave에 의해 보내진 table queue의 데이터를 처리하여 QC로 dequeue 하게 된다.

consumer slave와 producer slave로 나눠져있기 때문에 sort가 필요한 parallel execution에는 두배의 parallel query slave가 필요하게 된다.

 

* Table Queues

(TQ)는 process가 다른 process에레 row를 보내기 위한 queue이다. Table queue는 producer slave가 consumer slave에게, consumer slave가 query coordinator에게 데이터를 보내기 위해 사용된다.



3. Database Parameter Setup for Parallel Execution


PARALLEL_MAX_SERVERS 
인스턴스 당 최대 사용가능한 slave 개수. 0 설정시 parallel query 사용 불가.

PARALLEL_MIN_SERVERS 
instance startup 시 미리 띄워 놓을 slave 개수.

PARALLEL_MIN_PERCENT 

기본적으로 optimizer가 query를 parallel로 수행하도록 SQL 수행 계획을 생성되더라도 수행시 요구되는 parallel slave를 띄우기 위한 충분한 resource가 없을 경우, 사용자에게 특별한 메세지 없이 serial하게 query를 수행한다. 이러한 경우가 발생하면 query 수행시간이 예상보다 더 늦어지는 일이 발생할 수 있다.

PARALLEL_MIN_PERCENT는 수행시 충분치 못한 resource로 인한 parallel execution이 무시되는 경우를 방지하고 에러를 출력한다. PARALLEL_MIN_PERCENT는 가능한 parallel execution slave의 percent로 설정한다.

만약 설정한 percentage 만큼의 query slave를 띄울 수 없다면 serial로 수행하지 않고 ORA-12827 에러를 발생한다.

예) 만약 resource 부족으로 slave를 띄우지 못했을 경우:

0 에러 없이 serial execution을 수행한다.
50 best parallel execution time의 2배 정도까지의 execution time은 accept하고 에러 없이 수행
100 주어진 parallel query를 수행할 수 있는 resource가 없는 경우 ORA-12827 에러 발생.


OPTIMIZER_PERCENT_PARALLEL 

PARALLEL_ADAPTIVE_MULTI_USER

PARALLEL_ADAPTIVE_MULTI_USER init parameter가 TRUE로 설정되어 있을 경우 parallel execution 사용할 때 multi-user 환경에서의 성능 향상을 위한 algorithm을 사용하게 된다. 이 algorithm은 query가 수행되는 시점에 system load에 따라 자동으로 요청하는 parallel의 degree를 줄여 query를 수행한다. 

예를 들어 17 CPU 시스템에서 default parallel degree가 32로 설정되어 있다면 첫번째 사용자는 32개의 parallel slave process를 사용해 query가 수행된다. 그러나 두번째 사용자가 query를 수행할 경우 16개의 parallel slave process가 사용되며, 세번째 사용자는 8개, ..

결국 32번째 user는 1개의 parallel slave process를 사용하게 된다.

 

PARALLEL_AUTOMATIC_TUNING  new with 8i

다음의 내용은 PARALLEL_AUTOMATIC_TUNING에 의해 영향을 받는 Parallel execution parameter와 변경 방식이다.

Parameter

Default Values 
When parallel_automatic_tuning= 
 FALSE 

Default Values
When parallel_automatic_tuning=
TRUE

parallel_execution_message_size  2KByte 4KByte
parallel_adaptive_multi_user FALSE TRUE
large_pool_size

no effect 

is incerased based on
a complicated computation using 
various other parameters
processes

 no effect

if processes < parallel_max_servers
The processes parameter is increased
parallel_max_servers

5

if parallel_adaptive_multi_user==true
(cpus * parallel_threads_per_cpu * 
_parallel_adaptive_max_users * 5)
else 
(cpus * parallel_threads_per_cpu *
_parallel_adaptive_max_users * 8)


4. Parallel Execution Performance

Parallel query의 수행은 performance 상의 이점을 얻을 수 있으나 parallel queyr를 수행하기 앞서 몇가지 고려할 만한 사항이 있다.

multi-slave process는 당연한 얘기지만 single process 보다 많은 CPU resource와 slave process 각각의 private memory를 사용하게 된다. 만약 CPU 자원이 부족하게 되면 oracle은 parallel operation을 serial operation으로 변경해 작업을 수행한다. 따라서 parallel execution은 현재 system의 resource 상태를 고려해 parallel degree를 고려해야 한다.

또 I/O stress가 많은 시스템이라면 slave process에 의한 추가적인 I/O요구가 부담이 될 수 있습니다.
특히 I/O가 특정 disk에 집중된다면 disk I/O의 bottleneck이 발생할 수 있으므로 I/O의 분산 등도 고려되어야 한다.

parallel query는 Full Table Scan으로 데이터를 처리한다. 따라서 index의 사용이 유리한 경우에는 오히려 parallel execution의 성능이 더 나쁠 수 있다. 

이러한 성능의 차이는 index에 의해 query 조건의 선처리로 대상 데이터량을 줄이는데서 발생한다.

  •  Nested Loops vs. Hash/Sort Merge Joins
    Nested loop join의 경우 query 조건에 의한 "row elimination"으로 driviing table의 대상 row를 줄이기 때문에 FTS 보다는 index scan에 적합하다. 반면 Hash join과 sort merge의 경우 일반적으로 대량의 데이터를 처리하는데 더 효과적이다. 이는  Hash join과 Sort Merge join은 driving row source에 대해서 조건에 의한 데이터의 "row eliminate"를 하지 않기 때문이다. 
  •  slave process를 생성하고, data를 분할하고, 여러 slave process로 데이터를 전송하고 결과를 취합하는 등의 비용이 data를 serial하게 처리하는 것보다 많을 수 있다.
  •  Data skew
    parallel query는 데이터를 ROWID range를 기본으로 slave process 간에 할당한다. 각각의 slave에게 같은 개수의 block을 할당한다는 것은 같은 수의 row를 할당한다는 말과는 다른 의미이다. 예를 들어 대량의 데이터가 수집되고 삭제되는 업무의 경우 특정 블록들에는 데이터가 전혀 들어 있지 않을 수 있다. 이러한 균등하지 않은 데이터 분할로 인해 특정 slave query의 성능이 늦어질 수 있으며 이는 전체 PQ 처리 시간에 영향을 미치게 된다.


이 내용은 metalink.oracle.com의 note를 참조했습니다.

Note 203238.1 - Using Parallel Execution



* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



10G 이전에는 v$fast_start_servers, v$fast_start_transactions 두개의 view를 통해 parallel transaction recovery를 모니터링 할 수 있었습니다. 그러나 일반적인 transaction rollback이나 SMON에 의한 transaction recovery는 모니터링 할 수 없었죠.

그러나 10G에서는 transaction rollback monitoring 기능의 향상으로 일반적인 transaction rollback 작업과 SMON에 의한 transaction recovery에 대한 모니터링이 가능해 졌습니다. v$fast_start_servers, v$fast_start_transactions 두개의 view는 transaction recovery와 transaction rollback작업에 관한 historical 정보까지 갖고 있어 transaction recovery 관련되어 평균 rollback duration을 확인할 수 있습니다.

추가적으로 일반적인 transaction recovery 시간의 산정이 가능해졌으며, system performance에 맞춘 FAST_START_PARALLEL_ROLLBACK init parameter 설정도 가능합니다.

v$fast_start_transaction 의 STATE column은 RECOVERED, RECOVERING 등의 상태를 instance가 shutdown 될때까지 갖고 있어 현재 transaction 상태를 갖고 있으며, 작은 transaction은 보이지 않을 수 있습니다.

Example:
SELECT state,undoblocksdone,undoblockstotal,cputime FROM v$fast_start_transactions;

STATE         UNDOBLOCKSDONE        UNDOBLOCKSTOTAL CPUTIME
---------- -------------- --------------- ---------
RECOVERING     574                    1945             16

SQL> /
STATE         UNDOBLOCKSDONE         UNDOBLOCKSTOTAL CPUTIME
---------- -------------- --------------- ---------
RECOVERING     1300                     1945             34

SQL> /
STATE        UNDOBLOCKSDONE         UNDOBLOCKSTOTAL CPUTIME
---------- -------------- --------------- ---------
RECOVERED     1945                     1945              65

oracle metalink
Note 265198.1를 참조했습니다.

Note 265198.1 - Oracle 10G Transaction Rollback Monitoring





'Oracle Database' 카테고리의 다른 글

INTRODUCTION TO PARALLEL DML  (0) 2009.07.17
Oracle Parallel Query Execution  (1) 2009.07.16
Oracle index block split 현상  (7) 2009.07.10
SQL*NET Trace 설정하기  (0) 2009.07.10
Bulletin no : 12060 SQL*NET V2 최적화하기 [펌]  (2) 2009.07.08

Block split은 새로운 index key가 들어왔을때 기존에 할당된 block내에 저장할 영역이 없어 새로운 block을 할당 받는 index segment관련 operation 입니다.

Index Block Split은 새로 들어오는 index key 데이터에 따라 2개의 다른 방식으로 이루어 집니다.


1. index key 값이 기존의 index key 값에 비해 제일 큰 값이 아닐 경우 50/50  
   block split이 발생한다. 50/50 split은 기존에 존재하던 old block과 새로
   만들어진 new block에 50%의 데이터씩 채워져 split이 발생하게 된다.

2. index key 값이 기존의 index key 값에 비해 제일 큰값이 들어올 경우 99/1
   block split 이 발생한다. 99/1 split은 기존에 존재하던 old block에 99%의
   데이터가 있고 new block엔 새로운 데이터가 저장되게 된다.

이러한 index key의 저장 영역의 확인은 "analyze .. validate structure" 수행 후 index_stats view의 조회를 통해 확인 할 수 있습니다.

다음의 예는 간단한 테스트 입니다.

1. 계속 증가되는 데이터에 의해 99/1 split이 발생하는 예제 입니다.

SQL> drop table t1;
SQL> create table t1 (name varchar2(10),nr number) pctfree 0;
SQL> create index i1 on t1(nr);
SQL> declare
     i number;
     begin
     for i in 1..50000
     loop
     insert into t1 values('XX',i);
     end loop;
     end;
/

SQL> analyze index i1 validate structure;
SQL> select blocks, lf_blks, pct_used from index_stats;

Results:

BLOCKS: 104 LF_BLKS: 99 PCT_USED: 99


2. 데이터의 입력 순서를 바꿔 50/50 split이 발생하는 예제입니다.

SQL> drop table t2;
SQL> create table t2 (name varchar2(10),nr number) pctfree 0;
SQL> create index i2 on t2(nr);
SQL> declare
     i number;
     begin
     for i in 25000..50000
     loop
      insert into t2 values('XX',i);
     end loop;
     for i in 1..25000
     loop
      insert into t2 values('XX',i);
     end loop;
     end;
/

SQL> analyze index i2 validate structure;
SQL> select blocks, lf_blks, pct_used from index_stats;

Results:

BLOCKS: 256 LF_BLKS: 146 PCT_USED: 68

마지막의 blocks의 결과를 보시면 데이터의 입력 순서에 따라 데이터의 저장영역이 2배 이상 차이가 나는 것을 확인 할 수 있습니다.

이거 보시고 99/1로 index split을 하면 저장역역을 아낄 수 있겠지만,
예제1의 t1이 OLTP에서 여러 세션에 의해 insert 되는 table의 index라면
t1에 대한 insert 세션들이 index split을 기다리는 "
enq: TX - index contention"라는
block contention event를 오랫동안 만나실 수도 있습니다. ㅎㅎ

이 내용은 metalink note 183612.1을 참고했습니다.


요 몇일은 listener 관련해서 알아볼일이 많네요.
마지막으로 trace 설정하는 방법입니다.

Bulletin no : 12060 SQL*NET V2 최적화하기 [펌]

Listener 접속 단계 및 성능 측정




client쪽에 trace 설정 방법입니다.

TRACE_LEVEL_CLIENT = 0
TRACE_DIRECTORY_CLIENT = $ORACLE_HOME/network/trace (UNIX)
TRACE_FILE_CLIENT = client

server쪽에 trace 설정 방법입니다.

TRACE_LEVEL_SERVER = 0
TRACE_DIRECTORY_SERVER = $ORACLE_HOME/network/trace (UNIX)
TRACE_FILE_SERVER = SERVER

listener re-start 나 reload가 필요합니다...
OTN의 sql*net 최적화 하는 방법에 대한 bulletin 입니다.
나온지 꽤 지난 문서 같지만 엇그제 포스팅한 Listener 접속 단계 및 성능 측정 와 연관된 내용이라
같이 올립니다.


Bulletin no : 12060 
SQL*NET V2 최적화하기


1) PING
TCP/IP 네트워크상에서 ping을 사용해서 client와 server간에 걸리는 시간을 check할 수 있다.
만일 이 시간이 오래 걸리면 SQL*Net 보다 이 문제를 먼저 해결해야 한다.

사용 방법 :
ping 호스트이름
(NT의 경우에는 dos command상태에서)

2) TNSPING
이 tool은 기본적으로 설치가 되어 있으며 이 tool을 가지고 user가 client에 setting한 TNS alias(tnsnames.ora 파일안에 설정)
가 정상적으로 동작하는지를 테스트해 볼 수 있습니다.
TNSPING은 접속하고자하는 database가 있는 machine의 listener에 접속을하고 걸리는 시간을 miliseconds로 표시해 줍니다.
(실제 db와 connection을 맺는 것은 아닙니다.)

사용 방법 :
tnsping TNSalias이름
(NT의 경우에는 dos command상태에서)

3) 모든 logging 과 tracing 막기
Tracing 은 client와 server에 모두 가능하게 할 수 있습니다. 다음 parameter를 SQLNET.ORA파일과 LISTENER.ORA파일 ( $ORACLE_HOME/network(또는 net80)/admin에 위치합니다 )
에 setting하고 listener를 restart (lsnrctl stop, lsnrctl start) 하면 SQL*Net의 모든 tracing을 막을 수 있습니다.

   SQLNET.ORA:
   -----------
   TRACE_LEVEL_CLIENT =OFF
   TRACE_LEVEL_SERVER =OFF
   TNSPING.TRACE_LEVEL=OFF

   'OFF'대신에 '0'을 사용해도 됩니다.

   LISTENER.ORA:
   -------------
   TRACE_LEVEL_LISTENER=OFF
   LOGGING_LISTENER=OFF

4) Listener log 파일들 지우기
만 일 listener의 logging이 설정되어 있는 상태라면 LISTENER.LOG 파일이 이 생깁니다. listener는 connection이 맺어질대 마다 이 파일에 lock을 걸고 write하기 때문에 size가 계속 증가하게 되어 문제가 생길 수
있습니다. 만일 LISTENER.LOG 파일의 size가 너무 크게 되면 rename을 하시기 바랍니다. 그리고 listener를 restart하면 새로운 log file이 만들어 집니다.

5) SQLNET.ORA에 AUTOMATIC_IPC를 OFF로 설정
   AUTOMATIC_IPC = { ON | OFF }
위 parameter는 "SQLNET.ORA"파일에 설정할 수 있으며 ON으로 되어 있는경우 SQL*Net이 같은 alias정보를 가진 local database가 있는지 check하게 됩니다.
만일 local database가 있다면 connection은 network layer를 건너뛰고 local 'Inter Process Communication'(IPC)  connection을 맺게 됩니다.
따라서 이 setting은 database server쪽에 사용할 수 있는 것이지 client machine SQL*Net에는 아무 쓸모 없습니다.
database server쪽에 사용하더라도 local database에 SQL*Net connection이 반드시 필요한 경우가 아니라면 사용하시 않는 것(OFF로 설정)이 좋습니다.

6) SQLNET.ORA에 NAMES.DIRECTORY_PATH 설정
   NAMES.DIRECTORY_PATH = (ONAMES,TNSNAMES)
이 parameter는 TNS aliases를 찾는 경로를 지정할때 사용합니다. Oracle*Names가 설정이 안되어 있는 경우 ONAMES을 지우시는 것이 좋습니다.


7) SDU와 TDU
SDU('Session Data Unit')는 네트워크를 통해 보내는 packet의 size입니다. 이 size는 MTU(Maximum Transmission Unit)를 넘어서는 안됩니다. MTU는 네트워크상에 고정된 값입니다.
TDU('Transport Data Unit')는 SQL*Net이 data를 함께 묶는 기본 packet size 이며 SDU의 배수여야 합니다.

다음에서 예를 들어 보겠습니다.
   * SDU=1024, TDU=1536:

SQL*Net은 buffer에 1536 byptes까지 저장했다가 네트워크로 보냅니다. 낮은 network layer에서 이것을 다시 두개의 physical packets(1024,512 bytes)로 나누어 보냅니다.

   * SDU=1514, TDU=1000:
SQL*Net은 buffer에 1000 byptes까지 저장했다가 네트워크로 보냅니다. SDU는 request당 514 bytes를 더 담을 수 있는데도 불구하고 보내지기 때문에 network resource의 낭비를 초래합니다.

표준 Ethernet network에서 MTU의 default size는 1514 bytes입니다.
표준 token ring network에서 MTU의 default size는 4202 bytes입니다.

SDU와 TDU를 설정하려면 TNSNAMES.ORA 과 LISTENER.ORA 를 다음과 같이
바꾸어야 합니다.

   TNSNAMES.ORA:
   -------------
   ORCL.WORLD =
      (DESCRIPTION =
         (SDU=1514)
         (TDU=1514)
         (ADDRESS =
            (PROTOCOL = TCP)
            (HOST = fu.bar)
            (PORT = 1521)
         )
         (CONNECT_DATA = (SID = ORCL))
      )

   LISTENER.ORA:
   -------------
   SID_LIST_LISTENER =
      (SID_LIST =
         (SID_DESC =
            (SDU = 1514)
            (TDU = 1514)
            (SID_NAME = ORCL)
            (GLOBAL_DBNAME = ORCL.WORLD)
         )
      )

SDU와 TDU는 modem을 사용하는 환경에서는 줄여주는 것이 좋고 fiber나 T3 line을 사용하는 환경에서는 늘려주는 것이 좋습니다.
SDU와 TDU의 default값은 2048이고 maximum값은 32768입니다.


8) PROTOCOL.ORA의 tcp.no_delay 설정
기본적으로 SQL*Net은 SDU buffer가 찰때가지 request를 전송하지 않고 기다립니다. 다시 말해 request가 도착지점으로 바로 전송되지 않는 다는것을 의미 합니다.
그 런데 'no_delay'를 설정함으로써 data buffering을 하지 않게 할 수 있습니다. 따라서 'no_delay'를 설정하게 되면 작은 size의 patckets의 전송이 늘게되어 network traffic이 증가하게 됩니다.
따라서 이 parameter는 TCP timeout이 발생했을 경우에만 사용하셔야 합니다.

9) LISTENER.ORA의 QUEUESIZE 설정
QUEUESIZE는 listener가 저장할 수 있는 request의 수를 의미 합니다. 만일 들어오는 reqeusts의 수가 buffer의 size를 넘게 되면, 접속을 시도한 client는 접속을 실패하게 됩니다.
이 buffer의 size는 예상되는 동시 접속 수를 설정해 주는 것이 좋습니다.

   LISTENER =
     (ADDRESS_LIST =
           (ADDRESS =
             (PROTOCOL = TCP)
             (HOST = fu.bar)
             (PORT = 1521)
             (QUEUESIZE = 32)
           )
     )

이 parameter는  TCP/IP나 DECNET protocol이 사용될때만 사용됩니다.

10) SQLNET.ORA의 BREAK_POLL_SKIP 설정
이 parameter는 user break을 check하는 사이의 packet수를 지정합니다. 다시 말해 만일 이 parameter의 값이 높으면 CTRL-C checking은 덜 자주 일어나게되며 CPU overhead는 줄게 됩니다.
만일 이 parameter의 값이 낮으면 CTRL-C checking이 자주 발생되어 CPU overhead가 늘게 됩니다. 기본값은 4이며 client SQL*NET에만 사용됩니다.

11) SQLNET.ORA의 DISABLE_OOB 설정
Out of band break check를 enable시키거나 disable시킬때 사용하는 parameter입니다.
기본값은 off입니다.

여기서 잠간만 !
Out of Band Breaks란 무엇인가 ?
네트워크 통신상에서 받아들여지는 interrupt signals은 일반적으로 다른 data(예를 들어 select 문장)과 같이 도착하게 됩니다.
이것을 In-band Breaks라고 합니다. 그런데 이 interrupt signals을 connection과는 다른 channel을 통해 전달할 수 있습니다 이것을 Out of Band Breaks라고 하며 이 방식은
interrupt signal을 훨씬 빠르게 그리고 효과적으로 전달 할 수 있습니다. (예를 들어 deadlock을 break하기위해 control-C를 사용하는 것)

12) PROCESS.DAT와 REGID.DAT
7.3.2 버전에서 Oracle Server Tracing은 기본적으로 enabled되어 있습니다. 따라서 모든 connection과 request가 PROCESS.DAT와 REGID.DAT에
기록이됩니다. database의 사용기간이 길어지면 이 파일들은 접속속도를 현저히 떨어뜨리게 됩니다.
이러한 trace 파일들을 사용하지 않기위해 listener.ora파일에 'EPC_DISBLED=TRUE'를 설정해야 합니다.



Oracle Korea Customer Support Technical Bulletins




다음의 내용은 listener 접속시 지연현상에 대해 분석할 만한 방법에 대한 내용입니다.

요건 oracle metalink Note 214022.1를 참조한 내용입니다.

우선 SQLNET 관련 performance를 측정하기 위해서는 우선 sqlnet trace를 설정하고 그에 따라 소요 시간을 측정해야 합니다.

client에서 server side의 listener로 접속이전에 client 내의 connect descriptor에 대한 해석이 먼저 이루어 져야 합니다. oracle net trace file내에서 이 시점을 측정하기 위해서는 trace file이 생성된 시점과 "niotns: setting up interrupt handler"가 나오는 부분까지로 보시면 됩니다.

일반적으로 connect descriptor는 tnsnames.ora에 기술하여 사용합니다만.. 가장 빠른 방법은 command line에 다음과 같이 기술하는 방법입니다.

sqlplus scott/tiger@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS= / (PROTOCOL=TCP)(HOST=kareardo-pc)(PORT=1521))) / (CONNECT_DATA= SERVICE_NAME=iasdb.kareardo_pc.us.oracle.com)))

이 방법은 AP에 hard coding이 필요하므로 권장되는 방법은 아니지만, 성능 측정에서는 사용할만 합니다.

다음 방법은 잘 알려진 tnsnames.ora에 connect descriptor를 기술하는 방법입니다. 이때 NAMES.DEFAULT_DOMAIN 확장없이 속도를 측정해 볼 수 있습니다.

sqlplus scott/tiger@iasdb

다음은 NAMES.DEFAULT_DOMAIN 확장을 사용한 방법입니다.

sqlplus scott/tiger@iasdb.us.oracle.com

여기까지로 connect descriptor의 해석 과정을 측정해 볼수 있습니다.


또한가지 client에서 connect descriptor를 network protocol location이나 database service name으로 변경하는 단계에 영향을 줄 수 있는 것이 하나 더 있습니다. 그게 NAMES.DIRECTORY_PATH 입니다.

oracle net은 sqlnet.ora 내에 정의된 NAMES.DIRECTORY_PATH에 기술된 여러 방법을 참고해 connect descriptor를 가져오게 됩니다. 물론 default는 tnsnames.ora를 확인하는 방법이죠.

만약 oracle internet directory 등의 external naming method를 사용할 경우 external naming source에 대한 network round-trip이 필요합니다. 이러한 external naming source에 대한 속도는 network bandwidth나 system resource 등의 많은 부분에 영향을 받을 수 있습니다.

이러한 변수를 줄이기 위해서 oracle internet directory server가 위치한 동일 시스템에서 다음의 테스트를 진행해 볼수 있습니다.


Oracle Net이 connect descriptor를 network protocol-specific 정보로 변환하였다면 이제 드디어 oracle listener로 접속을 하게 됩니다.

일반적인 Network protocol은 응답이나 처리에서 오류가 발생할 경우를 대비한 응답 mechanism을 가지고 있습니다. 또 packet 실패의 경우 해당 packet을 재전송하는데, 이러한 network lose나 drop 등 network protocol 요소에 대한 tuning이 우선되어야 합니다.
(network protocol은 아는게 전혀 없으므로 통과 ~)

network protocol이 oracle listener로 접속된 이후에 listener는 여러가지 작업을 수행하는데, 그 중 부하가 높은 부분 중 하나가 server process를 생성하는 작업입니다.

일반적으로 process의 생성은 많은 메모리와 CPU, 시간을 소모하죠.
따라서 server process가 미리 생성되어 있다면 속도향상을 꾀할 수 있습니다. 이러한 환경이 pmon에 의해 미리 띄워지는 shared server 환경이죠..
그러나 요즘 shared server 환경은 많이 사용하지 않으므로 생략 합니다.
(왠지 날로 먹는 듯한... --;)

여기까지는 환경 설정 단계에서 잘설정하고 network에 큰 문제가 없으면 굳이 문제될 부분은 아닙니다만 주로 문제는 listener에 대한 동시 접속이 몰리는 경우에 발생합니다. 이런 경우 listener에 동시에 접속할 수 있는 queue 설정과 multi-listener를 설정합니다.

queue size의 경우 listener가 동시에 처리할수 있는 request 수를 지정해 줍니다. 이 값은 각 protocol의 설정값에 따라, system에 따라 달라지므로 적정값을 확인해 봐야 겠죠. multi-listener의 설정은 multi-cpu 환경에서 listener 가용성을 키우는 좋은 방법입니다.

   LISTENER =
     (ADDRESS_LIST =
           (ADDRESS =
             (PROTOCOL = TCP)
             (HOST = marvin)
             (PORT = 1521)
             (QUEUESIZE = 32)
           )
     )



* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



19 Direct-Path INSERT


Introduction to Direct-Path INSERT

오라클은 table에 데이터를 입력하는데 두가지 방식을 사용합니다.


  • 전통적인 insert operation은 table내의 free space를 재사용합니다. 기존의 데이터와 새로 insert 되는 데이터가 같이 저장되며, 참조 constraint도 자동으로 관리합니다.
  • direct-path insert operation은 새로 입력되는 데이터를 기존의 table내에 존재하는 데이터 이후에 저장합니다. buffer cache를 거치지 않고 바로 datafile에 저장되며, table내의 free space를 사용하지 않습니다. 또한 참조 constraint도 무시됩니다. 이러한 일련의 procedure로 인해 performance가 향상됩니다.

이러한 direct-path insert operation은 direct-path insert 구문이나 sql loader의 direct-path option을 이용해 사용될 수 있습니다. 


Advantages of Direct-Path INSERT

Direct-path insert는 다음의 performance 잇점을 갖습니다.


  • direct-path insert 시 redo와 undo entry들의 logging을 disable 할 수 있습니다. 반면 전통적인 insert operation은 free space 사용과 참조무결성을 위해 반드시 이러한 entry들에 대해서 logging을 해야 합니다.
  • 새 로운 데이터가 저장된 테이블을 생성하기 위해서 create table과 insert into를 사용하거나 create table .. as select 구문을 사용할 수 있습니다. create table 과 direct-path insert를 이용해 데이터를 insert 한 경우 기존 테이블에 존재하는 인덱스도 자동으로 변경됩니다. 반면 create table as select 구문을 사용한 경우 insert는 추후 재생성해야 합니다.
  • Direct-path insert는 serial/parallel mode 둘다 transaction이 하나의 단위로 처리된다 (transaction atomicity). 그러나 sql loader의 parallel-patch load의 경우 transaction atomicity를 보장하지 않는다.
  • parallel direct-path load의 경우 에러가 발생하면 index는 load 후 UNUSABLE로 빠질 수 있다. 반면 parallel direct-path INSERT 구문의 경우 index update시 에러가 발생하면 rollback 된다.

Serial and Parallel Direct-Path INSERT

parallel DML mode에서 insert 할 경우 direct-path INSERT가 default 이다. parallel DML mode로 사용하기 위해서 다음의 요구사항이 필요하다.


  • Oracle Enterprise Edition을 사용해야 한다.
  • ALTER SESSION { ENABLE | FORCE } PARALLEL DML; 명령으로 parallel DML 기능을 enable 해야한다. 
  • table 생성시 또는 그 이후 table에 대한 parallel attribute를 지정하거나 insert 구문내에 parallel hint를 지정한다.


direct-path INSERT를 disable 하기 위해 NOAPPEND hint를 insert 구문에 지정해 줘야 한다.

serial mode로 insert 할때 INSERT 구문 뒤에 APPEND hint를 사용하거나 INSERT 구문 내의 subquery의 SELECT 구문 바로 뒤에 APPEND hint를 지정해 줘야 한다.

Direct-Path INSERT Into Partitioned and Nonpartitioned Tables

Direct-path INSERT는 partition/non-partition table 모두 사용가능하다.

Serial Direct-Path INSERT into Partitioned and Nonpartitioned Tables

Single process insert의 경우 table segment나 각 partition segment의 HWM 뒤에 데이터가 insert 된다.

commit이 수행되면 HWM는 새로운 값으로 update 되며 user에게 데이터가 보이게 된다.

Parallel Direct-Path INSERT into Partitioned Tables

Partition table에 대한 parallel direct-path insert는 serial direct-path insert와 유사하다.

각각의 parallel execution server는 하나 또는 여러 partition에 할당된다. 하나의 partition에 대해 한개 이상의 parallel execution server process가 할당되진 않는다.

(Each parallel execution server is assigned one or more partitions, with no more than one process working on a single partition.)

각 parallel execution server는 할당된 partition segment의 HWM 이후에 데이터를 insert 한다.

commit이 수행되면 HWM는 update 되며 새로운 데이터는 user에게 보이게 된다.

Parallel Direct-Path INSERT into Nonpartitioned Tables

Non-partition table에 대한 parallel direct-path insert는 각각의 parallel execution server가 temporary segment를 만들며 이 temporary segment에 데이터를 insert 한다.

commit이 수행되면 parallel execution coordinator가 temporary segment를 table segment로 merge 한다.

Direct-Path INSERT and Logging Mode

Direct-path INSERT는 redo entry와 undo entry를 logging 할지를 선택 할 수 있다.


  • table, partition, index, LOB storage에 대해 생성시나 추후 logging mode를 설정할 수 있다. 
  • 만약 LOGGING이나 NOLOGGING을 설정하지 않았다면..
    • partition 의 경우 해당 table의 logging attribute를 따른다.
    • table이나 index의 경우 tablespace의 logging attribute를 따른다.
    • LOB storage의 경우 만약 CACHE option으로 정의 된 경우 LOGGING이 default attribute로 설정된다. 만약 CACHE option이 지정되지 않은 경우 해당 tablespace의 logging attribute를 따른다.
  • CREATE TABLESPACEALTER TABLESPACE 명령으로 logging attribute를 지정할수 있다.


Direct-Path INSERT with Logging

logging mode에서 direct-path insert가 수행될 경우 oracle은 full redo logging을 수행한다.


Direct-Path INSERT without Logging

NOLOGGING 으로 Direct-path insert 할 경우 oracle은 redo entry와 undo retry를 logging 하지 않습니다.

그러나 새로운 extent를 invalid로 marking하기 위한 최소한은 log와 data dictionary 변경에 대한 내용은 logging 합니다.

NOLOGGING은 performance를 증가시키지만 media recovery가 필요한 경우 redo 정보가 없기때문에 변경된 데이터에 대해 logical corruption을 발생하게 됩니다. 

따라서 NOLOGGING mode에서 direct-insert 한 경우 반드시 backup이 필요합니다.


Additional Considerations for Direct-Path INSERT

Index Maintenance with Direct-Path INSERT

오라클은 direct-patch INSERT 이후 table의 index에 대한 변경 사항을 적용합니다.

parallel direct-path INSERT의 경우 parallel execution server에 의해, serial direct-path INSERT의 경우 single process에 의해 수행됩니다.

Index 관리에 따른 performance 저하를 피하기 위해 insert 수행 전 index를 drop하고 rebuild 할 수 있습니다.

Space Considerations with Direct-Path INSERT

direct-patch INSERT의 경우 table의 free-list내의 공간을 사용하지 않기때문에 기존의 INSERT 방식에 비해 많은 공간을 요구하게 된다. 

serial direct-path INSERT와 partition table에 대한 parallel direct-path INSERT의 경우 해당 segment의 HWM 이후에 데이터를 저장하게 됩니다. 

이로 인해 추가적인 공간이 더 필요하게 된다. 


non-partition table에 대한 parallel direct-path INSERT의 경우 각각의 parallel degree 만큼의 temporary segment가 생성되어 추가적인 공간이 더 필요하다.

만약 non-partition table이 locally managed tablespace내에 automatic mode로 생성되지 않았다면 NEXT, PCTINCREASE, MININUM EXTENT 등의 storage parameter를

적정한 수치로 지정해 주어야 한다.


  • 각각의 extent size가 너무 작을 경우 object의 extent 갯수에 영향을 미친다.
  • parallel insert 결과가 segment내의 공간을 낭비하지 않도록 적당한 extent size를 갖어야 한다.


direct-path insert 이후 이들 storage parameter를 serial operation에 맞도록 다시 설정한다.

Locking Considerations with Direct-Path INSERT

direct-path INESRT 시 해당 table에 대한 exclusive lock이 요구된다. 따라서 다른 user들은 해당 table에 대해 insert, update, delete, index create/build operation이 제한된다. 

데이터에 대한 query는 지원되며 direct-insert 이전의 데이터만 보여진다.




'Oracle Database' 카테고리의 다른 글

Listener 접속 단계 및 성능 측정  (0) 2009.07.07
Oracle's Dev2DBA newsletter - 2009/07  (0) 2009.07.07
sequence cache & pining  (0) 2009.06.30
오라클의 에러  (0) 2009.06.25
Cluster I/O Fencing – exclusion strategy  (0) 2009.06.23

oracle 10g에서 소개된 Automatic Optimizer Statistics Collection 기능에 대해 간단히 얘기해보겠습니다. 대부분 이 기능을 끄고 안쓰는 걸로 알고 있는데 요놈 때문에 optimizer가 plan을 바꿔 곤란한 경우가 가끔 생기기도 합니다. 하지만 어찌 보면 굉장히 매력적인 기능이 아닐 수 없습니다. 대부분 데이터 베이스가 엄청 커져서 analyze 하는 시간도 오래 걸릴 뿐 아니라 더이상 오라클에서는 RULE base는 지원안한다고 하니..

그래서 지금은 안쓰지만 언젠가 쓰게될 요 기능에 대해 좀 알아보죠..

그러면 언제 automatic optimizer statistics collection이 시작 되며, 얼마나 수행될까요?
dba_scheduler_jobs를 보면 gather_stats_job이라는 job으로 등록되어 있습니다. 요 넘은 기본으로 저녁 10시 부터 8시간 동안, 또 토요일 00시 부터 2일 간 수행되게 되어 있죠.

만약 평일 8시간, 주말 2일간 수행을 다 못하면 어찌 될까요?
만약 수행 중 다 끝나지 않은 table의 statistic 정보는 원복 하게 됩니다.  그럼 다음날 에 다시 하겠죠? 아마 ~

그럼 얘는 뭘 보고 대상을 선정할 까요?
10g는 기본적으로 monitoring 기능이 enable 되어 있습니다. dba_tables 등의 view를 보면 monitoring이라는 column에 YES로 기본으로 박혀있죠.. dba_tab_modifications에 해당 table의 변경 내역을 저장하고 변경 내역이 10% 이상이 되면 STEAL 상태가 되어 Automatic Optimizer Statistics Collection의 대상이 됩니다.. 그리고 job이 수행되면 dba_tab_modifications의 데이터는 cleanup 됩니다.








RMA을 사용하기에 앞서 몇몇 고려할 사항들이 있습니다.

- Recovery Catalog 사용여부

Recovery Catalog는 RMAN에 의해서 사용되어지고 유지관리 되는 저장소입니다.
RMAN은 recovery catalog에 저장되어 있는 정보를 사용해서 요청되어진 Backup 과 Restore의 실행을 어떻게 할지를 결정하게 되는데, 이 catalog의 사용 여부가 우선 결정되어야 합니다. catalog 없이 RMAN 을 사용할 때의 단점은 recovery catalog 의 overhead 가 없는 대신, Point-In-Time recovery가 어려우며, control file 손상시에 recovery 할 수 없고, stored script 를 사용할 수 없습니다. 오라클에서는 RECOVERY CATALOG 사용을 권장합니다.

- Flash recovery area 사용.

oracle 10g에서 제공하는 flash recovery area는 rman에 의해 자동으로 관리됩니다.
물론 일반 disk나 tape으로도 backup이 가능하나, flashback database 등의 새로운 기능 등을 사용하려면 flash recovery area를 사용하는 것이 바람직합니다. 물론 disk 공간이 backup strategy에 충분할 정도는 있어야 겠죠.

- Backup Strategy

RMAN은 incremental backup이 가능하므로 full backup, incremental backup으로 backup strategy를 미리 정해야 합니다. 물론 저녁마다 full backup이 가능하다면 특별한 backup 전략은 필요 없겠지만요. (당신이 그러한 경우라면... 좋은 환경에서 일하시는 겁니다 ㅋ)

 * 백업 전략은 이전 post ( oracle - recovery manager (RMAN)) 를 참고

- RMAN configuration.

RMAN 관련한 default configuration 입니다.
(note 305565.1 Persistent Controlfile configurations for RMAN in 9i and 10g. 참고)

- CONFIGURE RETENTION POLICY TO REDUNDANCY 1;
Backup 보관 주기나 backup본의 갯수를 설정합니다.

- CONFIGURE BACKUP OPTIMIZATION OFF;
이미 backup 된 동일한(checkpoint SCN등) datafile, archived redolog, backup set이 있다면 skip 합니다.

- CONFIGURE DEFAULT DEVICE TYPE TO DISK; 
default backup device를 설정합니다.

- CONFIGURE CONTROLFILE AUTOBACKUP OFF; 
RMAN의 BACKUP이나 COPY 명령등의 수행후 자동으로 control file backup을 수행합니다.

- CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '%F';
autobackup되는 control file의 기본 format을 변경합니다.

- CONFIGURE DEVICE TYPE DISK PARALLELISM 1;
특정 device에 automatic channel allocation 될때 channel의 갯수를 지정합니다.

- CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE DISK TO 1;
DATAFILE, CONTROL FILE의 backup set의 copy본 갯수를 지정합니다.

- CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE DISK TO 1; 
ARCHIVELOG FILE의 backup set의 copy본 갯수를 지정합니다.

- CONFIGURE MAXSETSIZE TO UNLIMITED; 
backupset의 maximum size를 설정합니다.

- CONFIGURE ARCHIVELOG DELETION POLICY TO NONE; (10g only)
flash recovery area의 archived redo log에 대한 삭제 여부를 설정합니다.

- CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/opt/oracle/product/ora10g/dbs/snapcf_db10g.f';
RMAN은 resync시 생성되는 임시 snapshot control file의 이름을 지정한다.

RMAN에 관련된 configuration은 다음의 명령으로 확인 가능합니다.

RMAN> Show all;

CONFIGURE RETENTION POLICY TO REDUNDANCY 1; # default
CONFIGURE BACKUP OPTIMIZATION OFF; # default
CONFIGURE DEFAULT DEVICE TYPE TO DISK; # default
CONFIGURE CONTROLFILE AUTOBACKUP ON;
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '%F'; # default
CONFIGURE DEVICE TYPE DISK PARALLELISM 1; # default
CONFIGURE DATAFILE BACKUP COPIES FOR DEVICE TYPE DISK TO 1; # default
CONFIGURE ARCHIVELOG BACKUP COPIES FOR DEVICE TYPE DISK TO 1; # default
CONFIGURE MAXSETSIZE TO UNLIMITED; # default
CONFIGURE SNAPSHOT CONTROLFILE NAME TO '/u02/app/oracle/product/9.2.0/dbs/snapcf_V9201.f'; # default

그럼 다음 POST에선 RMAN 셋팅 방법에 대해 posting 하겠습니다.. ^^







RMAN 시작전에 알아야 할 몇몇 것(!) 들..

RMAN은 oracle8에서 처음 소개된 oracle에서 제공하는(!) backup & recovery tool 입니다.

Database files, Archive logs, 그리고 Control files들을 Backup하고 Restore하기 위하여 사용되어지며, Complete 또는 Incomplete Database Recovery 수행이 가능합니다. 또 10g 부터인가는 database의 validation check 까지 해 준다는 군요. (output을 보니 거의 DBV와 비슷한 내용인 것 같지만..)

다음은 RMAN에서 사용하는 주요 용어와 개념들 입니다.

- Target database
backup,restore,recovery action 이 수행될 대상 데이타베이스 입니다.

- Recovery Catalog
RMAN에서 사용하는 Information 저장장소입니다.
target database 의 물리적 스키마, datafile 과 archivelog 의 backup sets 과 pieces,
backup script 등을 포함하고 있습니다.

- channel
allocation channel 은 target database 의 backup,restore,recover에 대한 server process 초기화를 합니다. 즉, 이 channel은 disk 를 포함 기타 OS device를 지정하게 되며, 이에 따라 parallelization 의 degree 가 결정됩니다.

- Backup sets
하나 또는 그 이상의 Datafiles 또는 Archivelogs를 포함하며, 
Backup pieces의 Complate Set으로, Full 또는 Incremental Backup으로 구성 됩니다.
Oracle proprietary format을 사용합니다.

- Backup Pieces
하나의 Backup Set은 하나 또는 그 이상의 Backup Pieces로 구성이 되어지며,
각 Backup Piece는 Single Output File로  O/S의 File system Size의 제한을 갖고 있습니다.

[RMAN backup 내역 예]

RMAN> list backupset of database;
List of Backup Sets
===================
BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
21046   Full    957M       DISK        00:04:04     06-MAY-03  
        BP Key: 21047   Status: AVAILABLE   Tag: FULL_DB_SUNDAY_NIGHT
        Piece Name: /home1/kcshin/rman/backup/db_t493300635_s31_p1

  List of Datafiles in backup set 21046
  File LV Type Ckp SCN    Ckp Time  Name
  ---- -- ---- ---------- --------- ----
  1       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/system01.dbf
  2       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/undotbs01.dbf
  3       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/example01.dbf
  4       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/indx01.dbf
  5       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/tools01.dbf
  6       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/users01.dbf
  7       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/oem_repository.dbf
  8       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/kcshin01.dbf

- Image Copies
Single file( datafile, archivelog or controlfile)의 Copy 본으로 O/S의 copy와 매우 유사합니다.
Backup set이나 Backup Piece가 아니며, Compression이 수행되지 않는 제한이 있습니다.

[RMAN backup 내역 예]

RMAN> list copy of datafile '/home2/oradata/ORA920/kcshin01.dbf';
List of Datafile Copies
Key     File S Completion Time Ckp SCN       Ckp Time        Name
------- ---- - --------------- ----------    --------------- ----
21070   8    A 06-MAY-03       7238179754301 06-MAY-03       /home1/kcshin/rman/backup/datafile8.f

- Full Backup Sets
하나 또는 그 이상의 Datafiles에 대한 Backup으로 Datafile의 모든 사용되어진 Block을 포함합니다.
미사용 Block은 Backup되지 않으며, 압축형태로 저장됩니다.

[RMAN backup 내역 예]

RMAN> list backupset of database;
List of Backup Sets
===================
BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
21046   Full    957M       DISK        00:04:04     06-MAY-03  
        BP Key: 21047   Status: AVAILABLE   Tag: FULL_DB_SUNDAY_NIGHT
        Piece Name: /home1/kcshin/rman/backup/db_t493300635_s31_p1

  List of Datafiles in backup set 21046
  File LV Type Ckp SCN    Ckp Time  Name
  ---- -- ---- ---------- --------- ----
  1       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/system01.dbf
  2       Full 7238179754301 06-MAY-03 /home2/oradata/ORA920/undotbs01.dbf

- Incremental Backup Sets
하나 또는 그 이상의 Datafiles에 대한 Backup으로
같거나 낮은 Level의 이전 Backup이후 변경되어진 부분만 Backup을 하며, 압축형태로 저장됩니다.

[RMAN backup 내역 예]

RMAN> list backupset of database;
List of Backup Sets
===================
BS Key  Type LV Size       Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
21229   Incr 0  276M       DISK        00:01:06     06-MAY-03
        BP Key: 21232   Status: AVAILABLE   Tag: TAG20030506T155613
        Piece Name: /home1/kcshin/rman/backup/sunday_level0_493314973
  List of Datafiles in backup set 21229
  File LV Type Ckp SCN    Ckp Time  Name
  ---- -- ---- ---------- --------- ----
  1    0  Incr 7238179759787 06-MAY-03 /home2/oradata/ORA920/system01.dbf
  4    0  Incr 7238179759787 06-MAY-03 /home2/oradata/ORA920/indx01.dbf
  7    0  Incr 7238179759787 06-MAY-03 /home2/oradata/ORA920/oem_repository.dbf

- Recovery window
현재 시점과 recovery 가능한 가장 오래된 시점 사이를 나타내는 retention policy를 말합니다..

- SBT
System backup to tape

- Flash Recovery Area
control file, online redo log copies, archived logs, flashback logs 같은 recovery 와 관련된 file 들을 저장하기 위해 사용할 수 있는 선택적인 디스크 영역입니다.  오라클과  RMAN은 이러한 파일들은 flash recovery area 에 자동으로 관리합니다. 물론 일정 보관주기 설정이 가능하며, tape 등의 backup device로 backup이 가능합니다. flash recovery area는 target database에 설정됩니다.








가끔 database를 운영하다 보면 멀정히 잘 돌던 SQL이 plan이 바뀌어서 응답 시간이 터무니 없이 느려지곤 해 이로 인해 운영 장애가 발생하기도 하죠.

"같은 SQL을 같은 환경에서 사용하는데, SQL이 왜 느려지냐 ? "

뭐 이런 얘기를 DB 운영하는 사람이라면 가끔 들었을 법한 애기 입니다.
대개 이런 얘기는 높은 분들이 하기때문에 설명하기도 귀찮고 해서
그냥 "글쎄요.." 하고 넘어가기도 하는데,

사실 따지고 보면 데이터도 바뀌고, 변수값도 바뀌기 때문에
엄밀히 말하자면 같은 환경은 아닙니다.

bind peeking 기능으로 인해 hard parse 단계의 변수값에 영향을 받기도 하고,
automatic optimizer statistic collection 기능으로 인해 statistic 정보가 바뀔수도 있고,
dynamic sampling에 따라서 block 정보에 의해서도 바뀔수도 있죠.


이런 현상을 막으려면 부지런히 analyze 정보를 update 해주면 이러한 현상을 좀 줄어들 수도 있겠지만, 요거는 plan을 고정하기 보다는 plan을 최적화 한는 방법이죠.
뭐 잘되면 더 좋은 성능을 내겠지만,

그러나 다들 공감하시겠지만 성능 좋아진건 별로 눈에 띄지 않죠.
높은 분들도 잘 모르시고... ㅋㅋ

만약 특정 sql의 plan을 변경되지 않게 하기 위해서는 여러 방법이 있겠지만,
크게 outline을 사용하거나 hint를 sql에 적용하는 방법을 많이 사용합니다.

그러나 가끔 hint를 사용했는데, plan이 바뀌는 경우가 있는데, 이러한 경우는 대부분 hint를 꼼꼼히 부여하지 않아 optimizer가 hint를 무시하게 됩니다.

hint를 지정할때는 1) join method 2) join order 3) access method 를 전부 다 기술해 줘야 합니다.
요넘의 optimizer에게 일을 시키려면 절대 빠져나갈 구멍을 주면 안됩니다.. ㅋㅋ





가끔 오라클이 대량 작업 중에 죽거나 abort로 내렸을 경우
alert log에 보면 다음과 같이 SMON이 transaction rollback을 하는 메세지를 볼 수 있다.

SMON: about to recover undo segment 4
SMON: mark undo segment 4 as available
                    :


"음 .. 뭔가 큰 transaction이 있었군.."
"어? 왜 아직도 안끝나지? 언제 끝나는 거야? "


다음의 SQL은 rollback 대상 extent size를 확인할 수 있는 sql 문입니다.
이외에 undo segment header dump로 확인하는 방법도 있긴하지만,
요게 시간 산정하기는 더 편하겠지요..


select KTUXEUSN,KTUXESLT,KTUXESQN,KTUXERDBF,KTUXERDBB,KTUXESTA,KTUXESIZ
from x$ktuxe
where KTUXEUSN in (select segment_id from dba_rollback_segs where segment_name = '_SYSSMU156$')
and KTUXESTA = 'ACTIVE';



'Oracle Database' 카테고리의 다른 글

oracle 11g documents library  (0) 2009.01.18
대용량의 transaction rollback, 얼마나 걸릴까요?  (0) 2009.01.18
Oracle 9i online documents  (0) 2009.01.18
oracle 10g documents library  (0) 2009.01.18
Oracle AWR 이란?  (0) 2009.01.07

오라클 9i online documents 입니다.

Oracle 9i release 1 online documents
Oracle 9i release 2 online documents




오라클 10g documents library 입니다.

* oracle 10g release 2 (10.2) documents library 
* oracle 10g release 1 (10.1) documents library





오라클에서는 oracle의 성능을 측정하기 위한 몇몇 script를 제공해 왔습니다.

기본적으로 제공되던 script 들은 oracle version에 따라 utlbstat/utlestat, statspack, awr report 등의 형태로 제공되고 있습니다.

utlbstat/utlestat은 시작시점과 끝시점에 수행하여 구간의 데이터를 OS상의 text file로 출력하고,
oracle 8i 부터 제공되었던 statspack은 job이나 cron에 등록하여 구간별 데이터를 얻을 수 있게 되었습니다. awr report는 oracle 10g부터 제공되었으며, sql 수행정보등 level에 따라 좀더 다양한 성능관련 정보들을 보여 줍니다.

awr report는 기본적으로 60분 간격으로 7일간의 데이터를 수집, 보관합니다. 이 데이터는 SYSAUX tablespace에 보관되며, 다음의 performance view에 데이터를 저장하게 됩니다.

V$ACTIVE_SESSION_HISTORY - Displays the active session history (ASH) sampled every second.
V$METRIC - Displays metric information.
V$METRICNAME - Displays the metrics associated with each metric group.
V$METRIC_HISTORY - Displays historical metrics.
V$METRICGROUP - Displays all metrics groups.

DBA_HIST_ACTIVE_SESS_HISTORY - Displays the history contents of the active session history.
DBA_HIST_BASELINE - Displays baseline information.
DBA_HIST_DATABASE_INSTANCE - Displays database environment information.
DBA_HIST_SNAPSHOT - Displays snapshot information.
DBA_HIST_SQL_PLAN - Displays SQL execution plans.
DBA_HIST_WR_CONTROL - Displays AWR settings.

AWR report를 생성하기 위해서는 $ORACLE_HOME/rdbms/admin 밑에 있는 awr로 시작하는 몇몇 script를 수행하여 성능 보고서를 얻게 됩니다. 주로 awrrpt.sql이나 awrsqrpt.sql로 특정 구간의 성능데이터나 특정 구간에서의 SQL 수행정보를 얻곤 하죠.



다음은 awr관련 script 들입니다.

1)The awrrpt.sql SQL script generates an HTML or text report that displays
statistics for a range of snapshot Ids.

2)The awrrpti.sql SQL script generates an HTML or text report that displays
statistics for a range of snapshot Ids on a specified database and instance.

3) The awrsqrpt.sql SQL script generates an HTML or text report that displays
statistics of a particular SQL statement for a range of snapshot Ids. Run this report
to inspect or debug the performance of a SQL statement.

4) The awrsqrpi.sql SQL script generates an HTML or text report that displays
statistics of a particular SQL statement for a range of snapshot Ids on a specified SQL.

5) The awrddrpt.sql SQL script generates an HTML or text report that compares
detailed performance attributes and configuration settings between two selected
time periods.

6) The awrddrpi.sql SQL script generates an HTML or text report that compares
detailed performance attributes and configuration settings between two selected
time periods on a specific database and instance.

awr을 control 하기 위한 몇몇 procedure가 제공되는데,
DBMS_WORKLOAD_REPOSITORY.modify_snapshot_setting 은 interval이나 보관기간에 대한 설정을 위해 사용되며, DBMS_WORKLOAD_REPOSITORY.create_baseline는 성능 판단의 기준이 되는 baseline을 만들때 사용됩니다.

자세한 procedure 사용법은 다음과 같습니다.

How to Modify the AWR SNAP SHOT SETTINGS:
=====================================

BEGIN
  DBMS_WORKLOAD_REPOSITORY.modify_snapshot_settings(
    retention => 43200,        -- Minutes (= 30 Days). Current value retained if NULL.
    interval  => 30);          -- Minutes. Current value retained if NULL.
END;
/

Creating the Baseline:
======================

BEGIN
  DBMS_WORKLOAD_REPOSITORY.create_baseline (
    start_snap_id => 10,
    end_snap_id   => 100,
    baseline_name => 'AWR First baseline');
END;
/

Dropping the AWR baseline:
==========================

BEGIN
  DBMS_WORKLOAD_REPOSITORY.drop_snapshot_range(
(row_snap_id=>40,
High_snap_id=>80);
END;
/

Creating SNAPSHOT Manually:
===========================

BEGIN
  DBMS_WORKLOAD_REPOSITORY.create_snapshot();
END;
/

awr report는 수행 주기와 보관주기를 잘 선택해 놓으면, 정작 중요할 때 긴히 써먹을 수 있으니, SYSAUX tablespace 공간 아까워하지 말고, 좀 넉넉히 셋팅하는 것이 좋습니다..

위의 내용은 metalink.oracle.com의 아래 문서를 참조했습니다.

note 748642.1 What is AWR( Automatic workload repository ) and How to generate the AWR report?





DB 관리하면서 가장 긴장되는 순간이 ..
당연히 recovery를 수행해야 하는 순간이죠...

잘못하면 데이터 다 날라가거나,
아니면 restore하는데, 10여시간씩 걸리는데,
한번 잘못 명령어 날리면 ..

상상만 해도 끔찍하죠..ㄷㄷ

다음의 dictionary view는 recovery시 꼭 챙겨봐야 할 dictionary view 입니다.
돌다리도 두들겨 보고 건넙니다.. ^^


DBA_DATA_FILES, V$DATAFILE

: 해당 datafile의 현황 및 현재 상태를 check할 수 있다.

V$DATAFILE_HEADER

: 해당 datafile의 fuzzy 상태를 확인할 수 있다. 만약 fuzzy 상태라고 하면 v$backup에서 정상적으로 end backup이 수행되었는지,
추가로 archive log를 적용해야 하는지의 판단이 필요하다.

V$BACKUP

: 최종에 Online Backup받은 file들에 대한 정보를 가지고 있다.
즉, Hot Backup이 수행되고 있는 Tablepsace가 아직 Backup Mode로 있는지 아니면 Backup이 완료 된 상태인지 확인 할 수 있다.
만약 Online Backup을 수행 하면서 ALTER TABLESPACE ~ END BACKUP; 을 수행하지 않았다면 STATUS가 ACTIVE로 남아있게 되며, 
해당 file을 Backup받은 후에 ALTER TABLESPACE ~ END BACKUP command를 실행하지 않은 것이므로 즉시 ALTER TABLESPACE ~ END BACKUP command 를 실행해야 한다.

(fuzzy bit에 대한 자세한 내용..)

v$logfile, v$log

: archive log의 현황및 상태를 확인할 수 있다.

v$archived_log, V$LOG_HISTORY

: archive된 archive log의 정보를 controlfile로 부터 보여준다.

v$controlfile

: controlfile의 현황 정보를 확인할 수 있다.

v$tablespaces

: tablespace의 현황 정보를 확인할 수 있다.

V$RECOVERY_LOG

: media recovery를 위해 적용해야할 archive log의 정보를 확인할 수 있다.

V$RECOVER_FILE

: recovery가 필요한 datafile 정보를 확인할 수 있다.
 
V$RECOVERY_FILE_STATUS

: recovery를 수행하고 있는 oracle process에게 각각의 datafile의 recovery 정보를 보여준다. 다른 세션에서는 정보가 보이지 않는다.

V$RECOVERY_PROGRESS

: v$session_longops의 subview로 해당 recovery 작업 시간 산정등 recovery operation을 tracking 할때 사용한다.

V$RECOVERY_STATUS

: recovery를 수행하고 있는 oracle process에게 현재의 recovery process의 statistic 수치를 보여준다. 다른 세션에서는 정보가 보이지 않는다.



'Oracle Database' 카테고리의 다른 글

oracle 10g documents library  (0) 2009.01.18
Oracle AWR 이란?  (0) 2009.01.07
dba_ view와 v$ view (oracle dictionary view & dynamic performance view)  (0) 2009.01.03
oracle 10g RAC & CRS  (1) 2008.12.31
Oracle SQL plan 확인하는 방법  (0) 2008.12.16

오라클 모니터링 할 때 모니터링 툴을 많이 사용하시죠.
oracle의 Sql Developer, 웨어밸리의 Orange, 퀘스트의 TOAD, 엑셈의 MaxGuage, 데이타헤븐의 Intuvision,..

GUI tool을 사용하면 한눈에 시스템 전체를 파악하기 용이하고, 마우스 클릭 몇번으로 금방 정보를 확인할 수 있습니다. 그러나 oracle의 data dictionary view나 dynamic performance view의 모든 내용을 포함하기는 어렵고, 또 다 포함하고 있다고 해도 그에 대한 사용 방법에 대해 사용자가 인지하고 있긴 어렵죠.

일반적으로 DBA 들이 주로 사용하는 dictionary view는 열손가락 꼽을 정도 밖에 안되지 않을까 합니다. dba_users, dba_tablespaces, v$tablespace, dba_data_files, v$filestat, v$sysstat, v$session_wait ... (음, 10개는 넘겠군요.. )

그런데 dictionary view를 보면 dba_로 시작하는 view와 v$로 시작하는 view 들이 있습니다.
(물론, all_ 이나 user_, gv$로 시작하는 view 들도 있긴 하죠)

dba_ view와 v$ view의 차이점을 무얼까요?




이 차이에 대해 평소에 별로 생각해 본적이 없어 google에서 찾아 봤더니 oracle faq's blog에 잘 설명 되어 있네요.

Oracle FAQ's

V$% views return data from memory structures. Data is lost when the instance is restarted.
DBA_% tables return data from the database's data dictionary (SYSTEM tablespace). Data persists across instance restarts.

v$ view는 memory structure data를 보여주며, dba_ table(?)은 system tablespace 상의 data dictoinary data를 보여줍니다. 10g에서 awr 관련 view들이 만들어져서 dba_hist view 등에서 memory structure statistic data를 system tablespace에 저장해서 보여주기도 하죠.

다음의 HP's oracle blog에는 좀더 자세한 내용이 실려 있습니다..

HP's Oracle Blog

V$ & DBA_

Static Data Dictionary Views and Dynamic Performance Views are the core of database administration. They are of crucial importance. Whoever wants to learn Oracle database administration has to get familiar with these views.

The Data Dictionary tables contain meta data on objects, privileges, roles, users etc.
Whenever you issue DML statements Oracle consults its data dictionary to make sure a table is there, it has the right columns and you have privileges on it. And whenever you issue DDL statements Oracle updates its data dictionary.
All information needed by an instance on its database is kept in the data dictionary. Except some storage related information which is in the datafile headers and some information in controlfile and spfile which is needed at instance startup.

At runtime the oracle instance stores information about itself, about its CPU, memory or I/O performance, wait statistics and everything else which is going on at the instance in dynamic performance tables. Dynamic performance tables are non persistent. You can’t see past instance startup. After shutdown or instance crash all information contained in dynamic performance tables is lost. *1)

Through static dictionary views users can get at information kept in data dictionary tables.
And through dynamic performance views users can look at non persistent runtime information contained in dynamic performance tables.

But why are those views that important, you might ask? All information necessary for database administration can be found in those static dictionary views. And basically all information necessary for instance diagnostic and tuning can be obtained through those dynamic performance views at runtime.

Of course, GUI tools like Enterprise Manager or SQL Developer offer the same information
in a more user friendly manner. But all those GUI tools rely on static dictionary views and dynamic performance views.

As a DBA you will likely get into situations where there is no GUI tools available. At times you will be alone with your SQL*Plus skills. Your mastery of data dictionary and performance views will make all the difference!

동감입니다 !
tool을 사용하는 것이 더 효율적이라 생각하실지 모르지만
마지막엔 DBA가 직접 sqlplus에서 dictionary view들을 query해야 하는 경우가 허다하죠..

너무 툴에 익숙해지지 마세요.. ^^




왜 필요할 때 마다 이건 기억이 안나지.. 참..

현재 수행한 SQL의 plan을 확읺는 방법 2가지입니다..
select * from table(dbms_xplan.display);

SQL> desc dbms_xplan
FUNCTION DISPLAY RETURNS DBMS_XPLAN_TYPE_TABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 TABLE_NAME                     VARCHAR2                IN     DEFAULT
 STATEMENT_ID                   VARCHAR2                IN     DEFAULT
 FORMAT                         VARCHAR2                IN     DEFAULT

explain plan
for
sql ..

utlxpls.sql 수행
select plan_table_output from table(dbms_xplan.display('plan_table',null,'serial'));

SQL> desc dbms_xplan
FUNCTION DISPLAY RETURNS DBMS_XPLAN_TYPE_TABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 TABLE_NAME                     VARCHAR2                IN     DEFAULT
 STATEMENT_ID                   VARCHAR2                IN     DEFAULT
 FORMAT                         VARCHAR2                IN     DEFAULT

FUNCTION DISPLAY_AWR RETURNS DBMS_XPLAN_TYPE_TABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SQL_ID                         VARCHAR2                IN
 PLAN_HASH_VALUE                NUMBER(38)              IN     DEFAULT
 DB_ID                          NUMBER(38)              IN     DEFAULT
 FORMAT                         VARCHAR2                IN     DEFAULT

FUNCTION DISPLAY_CURSOR RETURNS DBMS_XPLAN_TYPE_TABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SQL_ID                         VARCHAR2                IN     DEFAULT
 CURSOR_CHILD_NO                NUMBER(38)              IN     DEFAULT
 FORMAT                         VARCHAR2                IN     DEFAULT

FUNCTION PREPARE_RECORDS RETURNS DBMS_XPLAN_TYPE_TABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 PAR1                           VARCHAR2                IN
 PAR2                           VARCHAR2                IN




active session들의 현재 wait event와 sql 정보를 buffer get 기준으로 보여주는 sql script 입니다.
세션 모니터링의 기본이죠..

<내용>
set pagesize 250
col sid for 9999
col waiting_on for a90
col serial# for 999999
col prg for a19
col OraPid for 9999
col command for a9
col aa Heading "DB-User" for a8
col bb Heading "OS-Pid" for a7

set pau off
select to_char(sysdate,'MM/DD HH24:MI:SS') dat,s.sid SID,s.serial#,sql_hash_value,
decode(s.command,
        '0','NO',
        '1','Cr Tab',
        '2','Insert',
        '3','Select',
        '6','Update',
        '7','Delete',
        '9','Create Idx',
        '10','Drop Idx',
        '15','Alter Tbl',
        '24','Create Proc',
        '32','Create Link',
        '33','Drop Link',
        '36','Create RBS',
        '37','Alter RBS',
        '38','Drop RBS',
        '40','Alter TBS',
        '41','Drop TBS',
        '42','Alter Sess',
        '45','Rollback',
        '47','PL/SQL Exe',
        '62','Anal Table',
        '63','Anal Index',
        '85','Truncate') Command,
substr(s.machine,1,8)||'['|| substr(s.program, 1, 9)||']' prg,
round(q.buffer_gets/q.executions,2) getperexec,
substr(
rtrim(w.event) || ': ' ||
rtrim(p1text,' ') || ' ' || to_char(p1) || ',' ||
rtrim(p2text,' ') || ' ' || to_char(p2) || ',' ||
rtrim(p3text,' ') || ' ' || to_char(p3),1,75) ||',waiting:'||wait_time  as waiting_on
from  v$session s, v$session_wait w,v$sqlarea q
where w.wait_time = 0
and w.sid = s.sid
and s.sql_hash_value = q.hash_value
and event not like '%pmon timer%'
and event not like '%smon timer%'
and event not like '%rdbms ipc message%'
and event not like '%SQL*Net message%'
and event not like '%lock manager wait for%'
and event not like '%slave wait%'
and event not like '%io done%'
and event not like '%pipe get%'
and event not like '%wakeup time manager%'
and event not like '%queue messages%'
order by getperexec
/




tablespace를 만들떄 local managed tablespace를 많이 사용하시죠?
예전의 dictionary-managed 방식에 비해 LMT는 많은 이점이 있죠..
뭐 이점이 있다기 보다는 dictionary-managed 방식의 단점이라고 보는게 더 타당할 지 모르겠네요..^^;

LMT의 extent 관리 방식에는 uniform size와 system managed 방식이 있습니다.
간단히 말하자면, uniform size는 extent size를 정해서 해당 tablespace에 생성되는 segment 들은 동일한 extent size로 설정되게 되고, system managed 방식은 extent size에 대한 설정을 oracle에서 관리해 주는 거죠..

system managed 방식을 쓰면 extent size에 대해 크게 신경을 안써도 되니 좋긴 한데, 오라클에서 어떻게 extent를 관리할까요?

심심해서 함 해봤는데, 엄청난 매카니즘이 숨겨 있더군요.. ㅋ


처음에 64k로 extent가 생성됩니다. 다음 extent도 64K가 생성되죠.. 뭐 이렇게 16개가 만들어지고,
다음은 1024K로 extent가 생성된후... 64개까지 만들어 지고...
..

이런 식으로 extent가 할당되면 1024K가 생성될 때 즈음이면
1024K 이하의 extent는 영원히 짜투리로 남을 수도 있겠죠?


LOCALLY MANAGED TABLESPACE IN ORACLE8I ...





+ Recent posts