ORACLE/ADMIN2013. 3. 4. 16:10
반응형

0g SYSAUX tablespace 크기 줄이기
오라클 2009/01/14 16:42
sysaux tablespace는 10g에서 새로 추가된 system default tablespace의 하나로 기존에 system tablespace에
저장되던 각종 ORACLE OPTION들의 schema가 저장되며 10g의 new feature인 AWR(auto workload repository) 데이터들이 저장되는 tablespace 입니다.
 
awr정보는 default로 1시간에 한번씩 data를 gathering하고 그 정보를 7일동안 저장하게 되어 있습니다.
7일이 지나면 가장 오래된 awr정보를 자동으로 삭제하게끔 되어 있습니다.
awr정보는 7일간 저장되지만 주기적으로 실행하는 table analyze 정보는 default로 31일 동안 저장이 됩니다.

<해결책>

1. select dbms_stats.get_stats_history_retention from dual;
(기본 31일입니다.)

2. exec dbms_stats.alter_stats_history_retention(7);
=> 일주일 주기로 바꿈
 
3.exec dbms_stats.purge_stats(to_timestamp_tz('10-10-2008 00:00:00 Asia/Seoul','DD-MM-YYYY HH24:MI:SS TZR'));
=> AWR(auto workload repository) 데이터 저장 값입니다. 디폴드 주기 31일 이지만
2008년 10월10일 이전 데이터 삭제 => 날짜 조정 해주시면 됩니다.
oracle 사용 내부 통계 정보로 자동 삭제 주기를 줄인 다음 값을 삭제 하는겁니다.

4.alter table wri$_optstat_histgrm_history enable row movement;

5.alter table wri$_optstat_histgrm_history shrink space;
5번 실행 해서 에러 없을 경우 진행
SQL> alter table wri$_optstat_histgrm_history shrink space;
alter table wri$_optstat_histgrm_history shrink space
*
1행에 오류:
ORA-10631: SHRINK clause should not be specified for this object
=> 에러 날 경우 6번 진행

6. 5번에서 에러 날 경우[index 생성 쿼리 추출 구문 실행]
set long 1000
select dbms_metadata.get_ddl('INDEX','I_WRI$_OPTSTAT_H_OBJ#_ICOL#_ST','SYS') from dual;

=>결과
CREATE INDEX "SYS"."I_WRI$_OPTSTAT_H_OBJ#_ICOL#_ST"
ON "SYS"."WRI$_OPTSTAT_HISTGRM_HISTORY"("OBJ#","INTCOL#",SYS_EXTRACT_UTC("SAVTIME"))
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSAUX" nologging;


select dbms_metadata.get_ddl('INDEX','I_WRI$_OPTSTAT_H_ST','SYS') from dual;

=> 결과
 CREATE INDEX "SYS"."I_WRI$_OPTSTAT_H_ST"
 ON "SYS"."WRI$_OPTSTAT_HISTGRM_HISTORY"(SYS_EXTRACT_UTC("SAVTIME")) PCTFREE 10 INITRANS 2 MAXTRANS 255
 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1
 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSAUX" nologging;

7. INDEX 삭제 아래 적용 후 재 생성
drop INDEX "SYS"."I_WRI$_OPTSTAT_H_OBJ#_ICOL#_ST";

drop INDEX "SYS"."I_WRI$_OPTSTAT_H_ST";
=============================================

8. alter table WRI$_OPTSTAT_HISTGRM_HISTORY enable row movement;

9. alter table WRI$_OPTSTAT_HISTGRM_HISTORY shrink space;

10. alter table WRI$_OPTSTAT_HISTGRM_HISTORY disable row movement;

11. alter session set workarea_size_policy=manual;

12. alter session set sort_area_size=104857600;

13. 위에서 삭제한 index 생성 쿼리 실행
13-1.
CREATE INDEX "SYS"."I_WRI$_OPTSTAT_H_ST"
 ON "SYS"."WRI$_OPTSTAT_HISTGRM_HISTORY"(SYS_EXTRACT_UTC("SAVTIME")) PCTFREE 10 INITRANS 2 MAXTRANS 255
 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1
 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSAUX" nologging;
13-2.
CREATE INDEX "SYS"."I_WRI$_OPTSTAT_H_OBJ#_ICOL#_ST"
ON "SYS"."WRI$_OPTSTAT_HISTGRM_HISTORY"("OBJ#","INTCOL#",SYS_EXTRACT_UTC("SAVTIME"))
PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "SYSAUX" nologging;

14.결과 조회
14-1
select occupant_name,space_usage_kbytes/1024 "MB"
from v$sysaux_occupants
order by space_usage_kbytes
/
적용 전
OCCUPANT_NAME                                         MB
--------------------------------------------- ----------

SM/OPTSTAT                                        4.8125
SM/AWR
적용 후

SM/OPTSTAT                                           3.5
SM/AWR

15. SYSAUX Tablespace 사용량 체크

select tablespace_name,sum(bytes/1024/1024) "Free(M)"
from dba_free_space
where tablespace_name = 'SYSAUX'
group by tablespace_name;

반응형
Posted by [PineTree]
ORACLE/SQL2013. 3. 1. 18:56
반응형

 

 

출처 : http://www.dator.co.kr/hotshin/textyle/236147

 

오라클 데이터베이스에서 선택된 행들에 대하여 배타적인 Lock을 설정 할 수 있는 기능이 SELECT FOR UPDATE 입니다. 요 기능에 대해서 잠시 살펴 봅니다. 어플리케이션에서 해당 기능을 프로그래밍 할 수도 있으나 오라클에서 제공되는 기능을 사용할 상황이 있겠죠.

활용하려는 상황

1. 특정한 테이블의 데이터(row)에 대하여 순차적 DML 처리를 가능하도록 하고자 하는 경우

2. 특정 데이터에 대해 동시 트랜잭션이 발생하여 데이터 정합성이 깨지는 것을 방지하고자 할 때

3. Update 처리 진행 중인 데이터를 다른 세션에서 읽는 것을 방지하고자 하는 경우

좀 장황해 보이네요. 좀 쉬운 표현으로는 A라는 사용자가 테이블의 특정 ROW UPDATE 하기 위해서 SELECT 하였으니까 다른 사용자들은 UPDATE 하지 말라는 것이죠.

활용 처

1. 영화 및 공연장의 특정 좌석을 예약하고자 한다.

2. 인터넷에서 판매되는 상품의 재고수량을 실시간으로 관리하고자 한다.

3. 은행의 예금 및 대출 통장의 잔액 변경의 일관성을 유지하고자 한다.

4. 인터넷 사이트의 포인트 잔액을 관리한다.

5. 기타 . . 등등

즉 하나의 리소스를 놓고 여러 트랜잭션에서 SELECT 한 후 INSERT/UPDATE/DELETE 로직을 처리하고자 할 때 먼저 SELECT 한 곳에서 리소스에 대해 LOCK을 걸고 COMMIT/ROLLBACK 하기 전에 다른 세션에서는 SELECT 되지 못하게 하는 기능이다. 프로그램적으로는 동시 처리하지 않고 순차적(Serial) 으로 처리 하라는 의미이다.

동시성 제어 시나리오
[그림1] 3명이 동시 상품구매 요청

그림1 동시상품구매.jpg

그림 한번 그려 보았네요. 잘 안보이죠. 더블 클릭. 따닥 ~~

[그림1]은 동일 상품에 대해 3명이 동시에 주문하려고 하였을 때 상품 수량의 변화를 나타내는 가상 시나리오이다. 특정 프로모션 기간일 때 다수의 사용자가 접속하여 상품을 주문하려고 하는 상황이다. 회사마다 이런 상황이 닥쳐을 때 대처하는 방법이 다를 수 있다. 어떤 회사는 업무 정책에 따라 동시성을 제어하지 않고 마이너스( - ) 수량 발생시 수작업 후속처리를 할 수 있고, 다른 회사는 수량 부족시 아예 에러를 발생시켜서 상품 부족시 주문발생을 억제 시킬 수도 있다.

SQL 구문

사용되는 구분과 예제를 살펴 봅니다. 오라클에서 LOCK은 테이블 단위가 아니라 처리할 데이터 ROW 레벨입니다.

1) FOR UPDATE with no option

LOCK를 획득하기 까지 무한정 기다린다.

해당 세션에서 transaction을 해제(commit, rollback) 하기 전까지는 결과셋에 대해서 lock이 걸림

SELECT A.*

FROM T_PRD_M A

WHERE PRD_CD = ' 10004'

FOR UPDATE;

2) FOR UPDATE nowait

lock를 회득하지 못하면 바로 exception 처리된다. (ORA-00054 오류 )

다른 세션에서 PRD_CD = ' 10004'에 대해서 lock을 잡고 있다면 에러가 발생

SELECT A.*

FROM T_PRD_M A

WHERE PRD_CD = ' 10004'

FOR UPDATE NOWAIT;

3) FOR UPDATE WAIT second

WAIT 시간() 만큼 동안 LOCK을 획득하기 위해 재시도한다.

주어진 시간 동안 LOCK을 획득하지 못하면 ORA-30006와 함께 해당 SQL문은 실패한다.

lock이 걸린 행들을 무한정 기다리게 되는 현상을 방지할 수 있으며, lock에 대한 대기 시간을 지정할 수 있기 때문에 로직 처리시간을 확보해야 하는 애플리케이션 개발에 사용 가능함.

SELECT A.*

FROM T_PRD_M A

WHERE PRD_CD = ' 10004'

FOR UPDATE WAIT 5; à 5초가 기다렸다가 lock을 획득하지 못하면 에러 발생

4) FOR UPDATE of

for update 구문은 FROM 절에 기술된 복수개의 테이블의 해당 행에 모두 LOCK을 설정한다. 이 때 of를 기술함으로 하여 특정 TABLE의 행에만 LOCK을 설정할 수 있다

SELECT A.*, C.*

FROM T_PRD_M A, T_CLS_M C

WHERE A.PRD_CD = '10004'

AND A.CLS_CD = C.CLS_CD

FOR UPDATE OF A.PRD_CD WAIT 5; à A테이블만 LOCK 겁니다.

FOR UPDATE OF C.CLS_CD WAIT 5; à C테이블에 LOCK을 겁니다.

FOR UPDATE OF WAIT 5; à A, B 테이블 모두에 LOCK 겁니다.

여기서 LOCK이 걸린다는 것은 위 SQL이 실행될 때 아래의 SQL들은 대기중으로 빠져서 기다린다는 이야기 겠죠

SELECT A.*, C.*

FROM T_PRD_M A, T_CLS_M C

WHERE A.PRD_CD = '10004'

AND A.CLS_CD = C.CLS_CD

FOR UPDATE OF A.PRD_CD WAIT 5;

동일한 SQL은 당연히 실행되지 않습니다

.

SELECT A.*

FROM T_PRD_M A

WHERE A.PRD_CD = '10004'

FOR UPDATE ;

T_PRD_M 10004 상품코드를 검색시 실행되지 않습니다. 당근 PRD_CD = ‘10005’는 실행되겠죠. LOCK 걸린 ROW가 아니기 때문에..

UPDATE T_PRD_M A

SET REG_ID = 'UPDATE'

WHERE A.PRD_CD = '10004';

어디선가 T_PRD_M 10004 상품코드를 UPDATE 하려고 한다면 LOCK 발생하여 대기상태로 빠집니다.

SELECT A.*

FROM T_PRD_M A

WHERE A.PRD_CD = '10004'

SQL은 정상적으로 실행 될까요 ?

빙고. LOCK과 상관이 없죠. 그냥 SELECT 됩니다.

SELECT FOR UPDATE 구문은 오라클 9부터 나온것이라고 하네요.

그리고 LOCK 걸린것은 commit; rollback; 될때 해제되겠죠

LOCK 세션 확인 쿼리는 아래와 같음.

SELECT A.SID, A.SERIAL#, B.TYPE, C.OBJECT_NAME

FROM V$SESSION A, V$LOCK B, USER_OBJECTS C

WHERE A.SID=B.SID

AND B.ID1=C.OBJECT_ID

AND a.schemaname= 'SH'-- 사용자명 넣기


동시성 제어 시나리오 2

[그림2] 동시 은행 입출금 처리

그림2 동시 입출금.jpg

그림2는 은행 예금 통장에서 여러 매체를 사용하여 입금 혹은 출금이 동시에 발생하는 예시입니다. 1개 통장의 입출금이 동시에 발생될 때 각각 처리 한다면 최종 잔액의 정합성을 보장할 수 없겠죠. 이때 입출금 처리를 Serial 하게 처리 해야 합니다. 위 상황에서도 SELECT FOR UPDATE 가 사용 될 수 있습니다.

조심해야 하는 것

뭐 모든 기능이 좋은 것이 있다면 단점도 있겠죠.

1) Select For Update 문장이 꼭 필요한 프로그램에서만 적용한다

- 일반 조회 및 검색 시에는 Select For Update를 사용하면 안 된다.

- 중요한 업무에 사용되는 테이블의 데이터 변경 시 동시성에 대한 제어를 하고자 하는 요건이 있는 경우에만 사용한다.

2) 동일한 SQL 처리 로직 구문에서는 동일한 Select For Update 구문을 사용하도록 함

3) Update 변경처리 직전에 “Select For Update”를 사용하여 check 및 검증용으로 사용한다.

4) 무분별한 lock의 사용은 시스템 리소스를 감소시키고, lock에 의한 시스템 중단이 발생 될 수 도 있다.

- Select For Update 구문이 들어가는 모듈을 공통화하고, 사용되는 SQL 본 수를 최소화 한다.

5) Program 및 프레임웍에서 Serial한 로직 처리가 가능한 경우 어플리케이션에서 해결 할 수 있도록 한다.

6) Select For Update 방식 중 가급적이면 “3. FOR UPDATE WAIT 시간” 를 사용하여 lock이 유지되는 것을 방지한다.

7) 대량 배치 처리시 해당된 모든 row에 대한 lock이 걸릴 수 있기 때문에 특별한 주의를 요한다.

8) Select For Update 구문을 사용하고자 할 경우 DA DBA에게 적용 사유를 공지한 후 사용하도록 한다. ( 이 구문을 사용하는 SQL과 프로그램 로직은 특별 관리 대상으로 선정한다 )

다음에는 Select For Update를 사용하지 않고 테이블과 데이터 발생규칙으로만 제어하는 사례를 살펴 보겠습니다.

반응형
Posted by [PineTree]
ORACLE/TroubleShooting2012. 12. 6. 16:40
반응형

출처 : http://blog.naver.com/1101kiho/90024390365



#####################

2pc pending 처리 사용예

######################

 

sqlplus as sysdba (sys권한으로 접속)

 

spool 20060715_2pc_pending
set time on
set timing on
set echo on

set pages 100

 

select * from dba_2pc_pending;

alter session set "_smu_debug_mode" = 4;

exec dbms_transaction.purge_lost_db_entry('8.16.204198');

commit;

select * from dba_2pc_pending;

spool off

 

 

 

#########################
# 2pc pending 처리 절차 #
#########################

DISTRIBUTED TRANSACTION TROUBLESHOOTING (ORA-1591해결 방법)

STEP 1: alert.log file을 check한다.
STEP 2: network 환경을 확인한다.
STEP 3: RECO process가 떠 있는지 확인한다.
        os> ps -ef | grep reco
STEP 4: DBA_2PC_PENDING을 조회해 본다.
        SQL>select local_tran_id, global_tran_id, state, mixed, host, commit#
        from dba_2pc_pending;
STEP 7: DBA_2PC_PENDING의 MIXED column을 확인한다.
      - MIXED값이 NO인 경우 : STEP 8 수행
      - MIXED값이 YES인 경우: STEP 9 수행

STEP 8: DBA_2PC_PENDING의 STATE column의 값을 확인한다.

 CASE 8-1: STATE field ---> COMMITTED인 경우
           SQL>exec dbms_transaction.purge_lost_db_entry('<TRANS_ID>');
           SQL>commit;

 CASE 8-2: STATE field ---> PREPARED인 경우  <-- Lock 인상태
           SQL>rollback force '<TRANS_ID>'; 혹은
           SQL>commit force '<TRANS_ID>';

 CASE 8-3: STATE field ---> COLLECTING인 경우
           SQL>exec dbms_transaction.purge_lost_db_entry('<TRANS_ID>');
           SQL>commit;

 CASE 8-4: STATE field ---> FORCED ROLLBACK/FORCED COMMIT 인 경우
           SQL>exec dbms_transaction.purge_lost_db_entry('<TRANS_ID>'); 
           SQL>commit;

STEP 9: 불일치 사항을 파악하고 DBA_2PC_PENDING을 정리한다.
   MIXED가 YES인 상태에서, inconsistency를 받아들이고 DBA_2PC_PENDING view를
   정리하려면 다음과 같이 수행한다.
           SQL>exec dbms_transaction.purge_mixed('1.8.238');
           SQL>commit;

================================================================
exec dbms_transaction.purge_mixed('1.8.238') 에러발생시 조치요령
에러내용
ERROR at line 1:
ORA-30019: Illegal rollback Segment operation in Automatic Undo mode
ORA-06512: at "SYS.DBMS_TRANSACTION", line 65
ORA-06512: at "SYS.DBMS_TRANSACTION", line 85
ORA-06512: at line 1

조치
alter session set "_smu_debug_mode" = 4;

# END #########################################################################


반응형
Posted by [PineTree]
ORACLE/ADMIN2012. 10. 12. 15:13
반응형

 

Sizing Redo Log Files

Sizing Redo Log Files

The size of the redo log files can influence performance, because the behavior of the database writer and archiver processes depend on the redo log sizes. Generally, larger redo log files provide better performance. Undersized log files increase checkpoint activity and reduce performance.
리두로그 파일 사이즈는 성능에 영향을 끼칠 수 있다, 왜냐하면 DBWR ARCn프로세스가 리두로그 사이즈에 영향을 받기 때문이다.
일반적으로, 큰 리두로그파일은 보다 나은 성능을 보장한다. 크기가 작은 로그파일은 chekcpint를 증가시키고 성능을 저하시킨다.

Although the size of the redo log files does not affect LGWR performance, it can affect DBWR and checkpoint behavior. Checkpoint frequency is affected by several factors, including log file size and the setting of the FAST_START_MTTR_TARGET initialization parameter. If the FAST_START_MTTR_TARGET parameter is set to limit the instance recovery time, Oracle Database automatically tries to checkpoint as frequently as necessary. Under this condition, the size of the log files should be large enough to avoid additional checkpointing due to under sized log files. The optimal size can be obtained by querying the OPTIMAL_LOGFILE_SIZE column from the V$INSTANCE_RECOVERY view. You can also obtain sizing advice on the Redo Log Groups page of Oracle Enterprise Manager.
비록 리두로그 파일 크기가 LGWR 프로세스의 성능에 영향을 주지는 않지만, DBWR 프로세스와 checkpoint에는 영향을 준다.
checkpoint 빈도는 리두로그파일 크기를 포함하여 FAST_START_MTTR_TARGET 파라미터등에 영향을 받는다.
만약 FAST_START_MTTR_TARGET 파라미터가 인스턴스 복구시간의 제한값으로 설정되면, 오라클 데이터베이스가
자동적으로 필요한 만큼의 checkpoint 빈도를 조절한다. 이 상황 하에서는, 리두로그 파일 사이즈는 작은 크기때문에
추가적인 checkpoint가 일어나는걸 방지하기 위해 충분히 크게 설정되어야 한다. 가장 최적의 사이즈에 대한 값은
V$INSTANCE_RECOVERY 뷰의 OPTIMAL_LOGFILE_SIZE 컬럼에서 확인이 가능하다. 또한 OEM의 Redo Log Group으로
부터도 확인 가능하다.

It may not always be possible to provide a specific size recommendation for redo log files, but redo log files in the range of 100 MB to a few gigabytes are considered reasonable. Size online redo log files according to the amount of redo your system generates. A rough guide is to switch log files at most once every 20 minutes.
리두로그 파일의 크기를 정확히 정하기는 힘들지만, 100MB에서 몇GB 까지가 합당하다. 리두로그 파일의 크기는 시스템이
생성하는 리두의 양에 따라 조절해야 한다. 대략 20분에 1번정도로 설정하면 된다.


[[리두로그 리사이징]]
*. REDO LOG group은 3개 이상 권장, member는 2개 권장
(member는 물리적으로 서로 다른 위치에 분산 권장)
*. 평상시 REDO LOG 스위치가 약 20분 이상 유지할 수 있는 Size 권장
(alert_TESTDB.log에서 지속적으로 모니터링해서 필요시 REDO LOG 크기를 증가시킬 것)
*. 체크포인트 간격 조절(initTESTDB.ora파라미터에서) fast_start_mttr_target = 600

*. DB Startup 상태에서 작업 가능

1. sqlplus 접속(Internal로 접속)
$> sqlplus '/ as sysdba'
OR
$> sqlplus system/manager

2. currunt REDO LOG 조회
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
1 1 43 104857600 2 YES INACTIVE 8485439 01-SEP-03
2 1 44 104857600 2 YES INACTIVE 8585874 02-SEP-03
3 1 45 104857600 2 NO CURRENT 8756665 03-SEP-03
STATUS가 Inactive인 경우만 작업 가능

3. REDO LOG file을 switch
SQL> alter system switch logfile;
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
1 1 46 104857600 2 NO CURRENT 8988801 03-SEP-03
2 1 44 104857600 2 YES INACTIVE 8585874 02-SEP-03
3 1 45 104857600 2 YES ACTIVE 8756665 03-SEP-03
SQL> alter system switch logfile;
SQL> select * from v$log;
GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM
---------- ---------- ---------- ---------- ---------- --- ---------------- ------------- ---------
1 1 46 104857600 2 YES ACTIVE 8988801 03-SEP-03
2 1 47 104857600 2 NO CURRENT 8990631 03-SEP-03
3 1 45 104857600 2 YES INACTIVE 8756665 03-SEP-03

4. acitive 한 REDO LOG group을 inactive로 변경
SQL> alter system checkpoint;

5. REDO LOG Drop
SQL> alter database drop logfile group 2;
6. REDO LOG logfile 삭제
SQL> !rm /oradata1/redo2a.dbf;
SQL> !rm /oradata2/redo2b.dbf;

7. REDO LOG logfile 추가
1) 멤버가 없는 경우
SQL> alter database add logfile group 2 '/oradata/redo2.dbf' size 100M;
2) 멤버가 있는 경우
SQL> alter database add logfile member '/oradata/redo2b.dbf' to group 2;
SQL> alter database add logfile
group 2 ('/oradata1/redo2a','/oradata2/redo2b') size 100M reuse;
3) 여러개의 REDO LOG 추가할 경우
SQL> alter database add logfile
group 4 ('/oradata1/redo4a','/oradata2/redo4b') size 100M,
group 5 ('/oradata1/redo5a','/oradata2/redo5b') size 100M,
group 6 ('/oradata1/redo6a','/oradata2/redo6b') size 100M;

[출처] DBMS관리 - 리두로그(REDO LOG) Resize 방법|작성자 smileDBA

반응형
Posted by [PineTree]
ORACLE/TUNING2012. 9. 7. 15:25
반응형

Current Page: http://www.bysql.net/index.php?document_srl=14752   <<==출처


7. Sort Area 크기 조정

  • Sort Area 크기 조정을 통한 튜닝의 핵심
    • 디스크 소트 발생 방지
    • 불가피 시, Onepass 소트 처리
  • 9i 부터 두가지 PGA 메모리 관리 방식 지원


(1) PGA 메모리 관리 방식의 선택

  • Work Area : 데이터 정렬, 해시 조인, 비트맵 머지, 비트맵 생성 등을 위해 사용되는 메모리 공간
  • 조정 파라미터 : sort_area_size, hash_area_size, bitmap_merge_area_size,create_bitmap_area_size
  • 8i까지 Work Area 기본 값을 관리자가 지정 및 직접 조정
  • 9i부터 "Automatic PGA Memory Management" 기능 도입으로 사용자가 일일이 그 크기 조정 하지 않아도 됨
    • 인스턴스 전체적으로 이용가능한 PGA 메모리 총량 지정 (pga_aggregate_target 파라미터)
  • 자동 PGA 메모리 관리
    • "workarea_size_policy = auto" (9i부터 Default 값 = "auto")
    • 오라클이 시스템 부하 정도에 따라 자동으로 각 세션에 메모리 할당
    • 이 파라미터의 설정 값은 인스턴스 기동 중에 자유롭게 늘리거나 줄일 수 있음
    • *_area_size 파라미터는 모두 무시되며 오라클이 내부적으로 계산한 값 사용
    • 시스템, 세션 레벨에서 '수동 PGA 메모리 관리' 방식 전환 가능

  • 수동 PGA 메모리 관리
    • "workarea_size_policy = manual"
    • 트랜잭션이 거의 없는 야간에 대량의 배치 job 수행 시 효과적
      • 자동 PGA 메모리 관리가 활성화 시, 프로세스 당 사용할 수 있는 최대 크기 제한으로 여유 메모리가 있어도 충분히 메모리를 활용하지 못해 작업 시간이 오래 걸릴 수 있음
    • Sort Area (최대 2,147,483,647 byte) 와 Hash Area 크기 조정


(2) 자동 PGA 메모리 관리 방식 하에서 크기 결정 공식
  • auto 모드의 단일 프로세스가 사용할 수 있는 최대 work area 크기 
인스턴스 기동 시 오라클에 의해 내부적으로 결정
_smm_max_size 파라미터로 확인 가능(단위 : KB)


  • Work Area 크기 조회
SELECT a.ksppinm name, b.ksppstvl VALUE
FROM   sys.x$ksppi a, sys.x$ksppcv b
WHERE  a.indx = b.indx  AND a.ksppinm = '_smm_max_size' ;


  • _smm_max_size 파라미터 값을 결정하는 내부 계산식
    • 9i 부터 10gR1 까지
_smm_max_size = least((pga_aggregate_target * 0.5), (_pga_max_size * 0.5))


☞ DB관리자가 지정한 pga_aggrate_target 의 5%와 _pga_max_size 파라미터의 50% 중 작은 값으로 설정


    • 10gR2 이후
      • pga_aggregate_target <= 500MB 일 경우

_smm_max_size = pga_aggregate_target * 0.2

      • 500MB < pga_aggregate_target <= 1000MB 일 경우
_smm_max_size = 100MB
      • pga_aggregate_target > 1000MB 일 경우
_smm_max_size = pga_aggregate_target * 0.1


  • _pga_max_size 파라미터 값
_pga_max_size = _smm_max_size * 2


  • AUTO 모드의 병렬 쿼리의 각 슬레이브 프로세스 사용가능한 work area 총량
  ☞ _smm_px_max_size 파라미터(KB)에 의해 제한

  • SGA : sga_max_size 파라미터로 설정된 크기만큼 공간 미리 할당
  • PGA : 자동 PGA 메모리 관리 기능을 사용하더라도 pga_aggregate_target 크기 만큼의 메모리를 미리 할당하지 않음
  • pga_aggregate_target 파라미터는 workarea_size_policy를 auto로 설정한 모든 프로세스들이 할당 받을 수 있는 work area의 총량을 제한하는 용도로 사용


(3) 수동 PGA 메모리 관리 방식으로 변경 시 주의사항

  • manual 모드로 설정한 프로세스는 pga_aggregate_target 파라미터 제약 받지 않음
  • sort area와 hash area를 아주 큰 값으로 설정하고 실제 매우 큰 작업을 동시에 수행한다면 가용한 물리적 메모리가 고갈돼 페이징(paging)이 발생하면서 시스템 전체 성능 저하 가능 (심할 경우, 시스템 마비까지 가능)

※ 참고) *_area_size 설정 가능 범위 : 0 ~ 2147483647 (2GB - 1Byte)

  • manual 모드에서 병렬 쿼리를 사용하면 각 병렬 슬레이블 별로 sort_area_size크기 만큼의 Sort Area 사용 가능
  • manual 모드에서 병렬 Degree를 크게 설정할 때는 sort_area_size와 hash_area_size 반드시 확인



(4) PGA_AGGREGATE_TARGET 의 적정 크기

  • 오라클의 권고 값

    • OLTP 시스템 : (Total Physical Memory * 80%) * 20%
    • DSS   시스템 : (Total Physical Memory * 80%) * 50%



(5) Sort Area 할당 및 해제

  • Sort Area 할당 시점과 해제 시점
    • 8i 전 : 소트가 수행되는 시점에 sort_area_size 크기만큼의 메모리 미리 할당
    • 8i 이후  : db_block_size 크기에 해당하는 청크(chunk)단위로 필요한 만큼 조금씩 할당
    • sort_area_size는 할당할 수 있는 최대 크기를 지정하는 파라미터로 바뀐 것

  • PGA 공간
    • 8i 까지 : PGA 공간은 프로세스가 해제될 때까지 OS에 반환하지 않음
    • 9i 부터 : 자동PGA 메모리 관리 방식 도입으로 프로세스가 더 이상 사용하지 않는 공간을 즉시 반환함으로써 다른 프로세스가 사용 가능 (버그로 인해 PGA메모리가 반환되지 않는 경우가 종종 있음)

  • Sort Area 가 할당되고 해제 되는 과정 측정 테스트

/* 세션별 현재 사용 중인 PGA, UGA 크기, 가장 많이 사용 했을 때 크기 측정 쿼리 */


SELECT ROUND( MIN( decode( n.name , 'session pga memory' , s.value ) ) /1024 ) "PGA(KB)" ,

       ROUND( MIN( decode( n.name , 'session pga memory max' , s.value ) ) /1024 ) "PGA_MAX(KB)" ,

       ROUND( MIN( decode( n.name , 'session uga memory' , s.value ) ) /1024 ) "UGA(KB)" ,

       ROUND( MIN( decode( n.name , 'session uga memory max' , s.value ) ) /1024 ) "UGA_MAX(KB)"

FROM   v$statname n ,

       v$sesstat s

WHERE ( name LIKE '%uga%'

        OR   name LIKE '%pga%' )

AND    n.statistic# = s.statistic#

AND    s.sid = &sid


    • 자동 PGA 메모리 관리 방식으로 시스템 레벨에서 사용할 수 있는 총량을 24MB로 제한

/* 테스트 환경 설정*/


alter system set pga_aggregate_target = 24M;


CREATE TABLE t_emp AS

SELECT *

FROM   emp , SELECT ROWNUM no FROM dual CONNECT BY LEVEL <= 100000 ) ;


    • order by 절을 포함하는 쿼리 수행

SELECT * FROM   t_emp ORDER  BY empno ;

  • 최초  : 쿼리 수행 직전
  • 수행도중  : 쿼리가 수행 중이지만 아직 결과가 출력되지 않은 상태 (→ 값이 계속 변함)
  • 완료 후  : 결과를 출력하기 시작했지만 데이터를 모두 fetch하지 않은 상태
  • 커서를 닫은 후  : 정렬된 결과집합을 끝까지 fetch하거나 다른 쿼리를 수행함으로써 기존 커서를 닫은 직후

   ▼ 위의 쿼리 측정 결과 요약 표

  단    계 

           PGA(KB) 

    PGA_MAX(KB) 

          UGA(KB) 

    UGA_MAX(KB) 

  최초

376 

632 

153 

401 

  수행 도중 

5,560 

6,584 

4,308 

5,331 

  완료 후

3,000 

6,584 

2,774 

5,331 

  커서를 닫은 후    

376 

6,584 

153 

5,331 


    • 수행 도중'과 '완료 후' 에 UGA, PGA 크기가 MAX 값을 밑도는 이유

    ☞ 소트해야 할 총량이 할당 받을 수 있는 Sort Area 최대치 초과

                    ☞ Sort Area 초과마다 중간 결과집합(sort run)을 디스크에 저장하고 메모리를 반환했다가 다시 할당 받음


  • 수동 PGA 메모리 관리 방식으로 전환 테스트

alter session set workarea_size_policy = MANUAL;

alter session set sort_area_size = 52428800;

alter session set sort_area_retained_size = 52428800;


SELECT * FROM   t_emp ORDER  BY empno ;


    ▼ 위의 쿼리 측정 결과 요약 표

  단    계 

           PGA(KB) 

    PGA_MAX(KB) 

          UGA(KB) 

    UGA_MAX(KB) 

  최초

376 

6,584 

153 

5,331 

  수행 도중 

48,760 

52,792 

43,049 

47,077 

  완료 후

4,792 

52,792 

4,315 

47,077 

  커서를 닫은 후    

440 

52,792 

153 

47,077 


☞ manual 모드로 설정한 프로세스는 이 파라미터의 제약을 받지 않음

   ( ∵ 파라미터로 설정한 값보다 더 큰 값 52,792(KB) = 54059008 byte 까지 도달 )



반응형
Posted by [PineTree]
ORACLE/TUNING2012. 9. 6. 14:29
반응형

http://docs.oracle.com/cd/B19306_01/server.102/b14237/initparams157.htm 

PGA는 각각의 프로세스에서 개별적으로 사용되는 메모리 영역을 말한다. 이 PGA는 크게 아래와 같이 4개로 나누어져 있다. 

정렬 공간 : 명시적 또는 묵시적으로 정렬작업이 발생할 때 사용된다. 이 공간에서 정렬작업이 완료된다면 메모리 정렬이라고 하고 작업량이 이 메모리 영역을 넘어설 경우 disk 를 사용하게 된다.
세션 정보 : 유저 프로세스의 세션정보를 저장한다.
커서 상태 정보 : SQL 파싱 정보가 저장되어 있는 주소를 저장한다.
변수 저장 공간 : SQL 문장에서 사용했던 BIND 변수를 저장한다.



9i부터 PGA 메모리 영역의 크기를 automanual 두가지 방법으로 관리한다.
AUTO으로 관리한다면
 PGA_AGGREGATE_TARGET 파라미터를 설정해야 하고 manual 으로 한다면  *_AREA_SIZE  파라미터 값을 설정해야 한다.

WORKAREA_SIZE_POLICY=AUTO|MANUAL


 



AUTO ( PGA_AGGREGATE_TARGET  )

PGA_AGGREGATE_TARGET는 PGA 메모리 관리를 Auto 로 했을 때 사용되는 파라미터이다. 

주의 

이 값을 0으로 설정하면 자동으로 WORKAREA_SIZE_POLICY=MANUAL 으로 된다.



 

Property Description
Parameter type Big integer
Syntax PGA_AGGREGATE_TARGET = integer [K | M | G]
Default value 10 MB or 20% of the size of the SGA, whichever is greater
Modifiable ALTER SYSTEM
Range of values Minimum: 10 MB

Maximum: 4096 GB - 1

Basic Yes


 
AUTO 로 관리될 경우 PGA_AGGREGATE_TARGET 에 설정 크기내의 가용 메모리 내에서 PGA 크기가 자동으로 조정된다.
말이 좀 어려운데  PGA_AGGREGATE_TARGET는 생성되는 모든 PGA가 사용 할 수 있는 총 메모리 크기이다. 그러므로 예를 들면 PGA_AGGREGATE_TARGET =10M 일때 현재 1mb를 사용중인 Process 가 2개가 있다면 현재 가용 메모리 양은 8MB 가 된다.

만약 크기를 정하지 않으면 기본값은 10Mb 와 SGA 크기의 20%중 큰 값으로 설정된다.

 예를들어 만약  PGA_AGGREGATE_TARGET 이 50MB 이고 현재 PGA크기가 5MB 인 서버프로세스가 10MB 작업공간이 필요한 정렬작업을 수행시 자동으로 10MB의 메모리를 할당받게 되어 메모리 정렬이 일어나게 된다.


MANUAL ( SORT_AREA_SIZE ) 

 이전 버전에서는 SORT_AREA_SIZE 를 설정하여 각 서버 프로세스별로 동일한 크기의 PGA 를 할당하여 사용했었다. 이 방법은 관리가 간단한 반면 메모리 사용이 비효율적일 수 있다. 
 각 PGA는 SORT_AREA_SIZE 크기 만큼의 정렬공간을 할당받는다. 예를 들어 SORT_AREA_SIZE가 5M일 때 10MB 의 공간이 필요한 정렬 작업이라면 디스크I/O가 발생하게 된다. 


주의 사항
 분명 WORKAREA_SIZE_POLICY=AUTO 방법으로 사용하는 것이 융통성이나 효율면에서 이점이 있는것이 분명하다. 하지만 주의 할 점은  PGA_AGGREGATE_TARGET=100M 인데 어떤 서버 프로세스의 PGA에서 100MB 할당 받아버리면 다른 사용자가 접속할 수 없게 된다. 그러므로 이를 위해 잘 파악하고 사용해야 한다.




현재 PGA 메모리 사용량과 최대 메모리 사용량 조회

-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   select PROGRAM, PGA_USED_MEM, PGA_ALLOC_MEM, PGA_MAX_MEM 
   from v$process
   order by 1;
     
 -- 결과
PROGRAM                                          PGA_USED_MEM PGA_ALLOC_MEM PGA_MAX_MEM 
------------------------------------------------ ------------ ------------- -----------
PSEUDO                                                      0             0           0
oracle@server1 (ARC0)                                10755245      22907169    22907169
oracle@server1 (ARC1)                                10767957      22907169    22907169
oracle@server1 (CJQ0)                                  465021       1480333     1480333
oracle@server1 (CKPT)                                  301197        609233      609233
oracle@server1 (D000)                                  555241       1218189     1218189
oracle@server1 (DBW0)                                  274557       1933613     1933613
oracle@server1 (J000)                                  257157       1087117     1087117
oracle@server1 (LGWR)                                10769773      22910077    22910077
oracle@server1 (MMAN)                                  214137        366221      366221
oracle@server1 (MMNL)                                  218217        431757      431757
oracle@server1 (MMON)                                 1248501       2725517     2856589
oracle@server1 (PMON)                                  213713        366221      366221
oracle@server1 (PSP0)                                  212937        366221      366221
oracle@server1 (QMNC)                                  215281        366221      366221
oracle@server1 (RECO)                                  352437        497293      497293
oracle@server1 (RVWR)                                  211073       3118733    17929869
oracle@server1 (S000)                                  122889        300685      300685
oracle@server1 (SMON)                                  465737       1283725     1349261
oracle@server1 (TNS V1-V3)                             326625        645417      645417
oracle@server1 (TNS V1-V3)                             309549        579881      579881
oracle@server1 (TNS V1-V3)                             326625        645417      645417
oracle@server1 (TNS V1-V3)                             326625        645417      645417
oracle@server1 (q000)                                  314445        562829      562829
oracle@server1 (q001)                                  231081        366221      366221

-

위의 결과에서 highlight 된 부분이 Server Process 이다. 

각 컬럼에 대해 설명하자면 
PGA_USED_MEM : 프로세스가 현재 사용하는 PGA 크기.
PGA_ALLOC_MEM : 프로세스에 할당된 PGA 크기
- 다른 프로세스에서 필요로 할 경우  
PGA_USED_MEM  를 제외한 나머지 공간을 반환한다. 즉  PGA_ALLOC_MEM  만큼 할당되어 있지만 현재는  PGA_USED_MEM  만 사용중이고 남은 메모리는 반환되지 않았음을 의미)
PGA_MAX_MEM : 프로세스가 가장 많이 사용했을 때의 크기

반응형

'ORACLE > TUNING' 카테고리의 다른 글

DBMS_XPLAN.DISPLAY_CURSOR 결과 보는 법  (0) 2013.06.23
Sort Area 크기 조정  (0) 2012.09.07
PGA(Program Global Area) 관리  (0) 2012.09.06
Latch: cache buffers chains  (0) 2012.09.06
Oracle Wait Event 모니터링  (0) 2012.05.02
Posted by [PineTree]
ORACLE/TUNING2012. 9. 6. 14:22
반응형

PGA(Program Global Area) 관리

PGA는 오라클 서버 프로세스에 의해 생성되며 DB에 접속하는 모든 사용자에게 할당되는 오라클 메모리 영역인데 아래에서 이 영역을 관리하는 방법에 대해 알아 보겠습니다.

우선 PGA를 구성하는 영역에 대해 알아보면… Sort Area(Order Bu, Group By의 경우에 사용), Session Information(서버 프로세스에 의해 추출된 결과값을 클라이언트의 사용자 프로세스에 전달하기 위해 필요한 사용자 프로세스의 정보 저장), Cursor State(SQL의 파싱 정보 저장), Stack Space(Bind 변수를 저장)로 구성되는데 이를 관리하기 위해서는

다음과 같은 파라미터의 설정이 필요 합니다.

WORKAREA_SIZE_POLICY : manual 또는 auto의 값이 들어올 수 있는데 auto인 경우 PGA_AGGREGATE_TARGET 파라미터를 이용하여 PGA 크기를 설정하겠다는 의미이며 manual인 경우 SORT_AREA_SIZE 설정을 통해 소트 영역을 설정하겠다는 의미 입니다.

SORT_AREA_SIZE : 정렬을 위한 공간을 설정

PGA_AGGREGATE_TARGET : 모든 사용자 세션이 사용할 총 PGA 크기를 지정. 즉 이 크기만큼 모든 사용자 세션이 사용할 수 있으며 이는 오라클서버에서 자동으로 관리 됩니다.

이전 오라클 버전에서는 SORT_AREA_SIZE 크기를 설정하여 세션별로 지정된 크기의 PGA를 할당하였는데 9i 및 10g에서는 세션별로 정해진 PGA의 크기가 아닌 전체 세션에 할당될 총 PGA SIZE를 PGA_AGGREGATE_TARGET을 통해 설정하게 되어 있는것이죠…

DB에 한 사용자가 접속하였고 이때 SORT_AREA_SIZE는 10M 였다고 가정할 때 사용자가 50M되는 테이블을 정렬한다고 할 때 WORKAREA_SIZE_POLICY가 manual인 경우라면 SORT_AREA_SIZE 10M를 넘어서는 경우이므로 TEMP Tablespace를 사용하여 정렬을 하게 될 겁니다(SORT가 메모리에서 일어나면 좋지만 공간이 부족하여 디스크에서 일어난다면 성능에 문제가 있을 수 있습니다). 이 경우엔 5번정도 DISK IO가 일어나므로 성능에 영향을 줄 수가 있겠죠… 그런데 WORKAREA_SIZE_POLICY를 auto로 설정하고 PGA_AGGREGATE_TARGET 파라미터를 최소 50M 이상 준다면 DISK IO 없이 충분히 메모리 SORT가 가능할 겁니다. 물론 여러 사용자가 있으니 PGA_AGGREGATE_TARGET의 크기는 충분히 고려되어야 할겁니다.

평상 시 사용되는 PGA의 크기는 v$session을 통해 조회할 수 있는데 간단히 보시면  PGA_USE_MEM을 통해 프로세스에서 현재 사용되는 PGA 크기를 알수 있으며 PGA_ALLOC_MEM 컬럼을 통해 프로세스에 할당된 PGA 크기, PGA_MAX_MEM 컬럼을 통해 프로세스가 사용한 최대 메모리 사용량을 알 수 있습니다.

감사합니다.
[출처] [Oracle강좌] PGA(Program Global Area) 관리 |작성자 오라클러

반응형

'ORACLE > TUNING' 카테고리의 다른 글

Sort Area 크기 조정  (0) 2012.09.07
SORT와 PGA_AGGREGATE_TARGET  (0) 2012.09.06
Latch: cache buffers chains  (0) 2012.09.06
Oracle Wait Event 모니터링  (0) 2012.05.02
Chapter 9 Tuning Buffer Cache  (0) 2012.05.02
Posted by [PineTree]
ORACLE/TUNING2012. 9. 6. 14:09
반응형

Latch: cache buffers chains

목차

[숨기기]

[편집] Basic Info

버퍼 캐시를 사용하기 위해 해시 체인을 탐색하거나 변경하려는 프로세스는 반드시 해당 체인을 관리하는 cache buffers chains 래치를 획득해야 한다. cache buffers chains 래치를 획득하는 과정에서 경합이 발생하면 latch: cache buffers chains 이벤트를 대기하게 된다.

오라클 9i 이후부터는 읽기 전용의 목적으로 체인을 탐색하는 경우에는 cache buffers chains 래치를 Shared 모드로 공유할 수 있어 경합을 줄이는데 도움이 된다. Shared 모드의 cache buffers chains 래치에 대해 한가지 주의할 점이 있다. 만일 cache buffers chains 래치를 공유할 수 있다면 이론적으로는 동시 Select에 의한 cache buffers chains 래치 경합은 전혀 발생하지 않아야 한다. 하지만, 실제로 테스트를 해보면 동시 Select인 경우에도 래치 경합은 여전히 발생한다. 그 이유는 Buffer Lock과 관련이 있다. 읽기작업을 위해서 Shared 모드로 래치를 획득한 경우, 실제 버퍼를 읽는 과정에서 Buffer Lock을 Shared 모드로 획득해야 하는데 이 과정에서 버퍼 헤더의 정보를 일부 변경해야 한다. 따라서 Buffer Lock을 획득하는 동안에는 래치를 Exclusive 모드로 변경해야 하고Buffer Lock을 해제하는 동안에도 래치를 Exclusive하게 획득해야 한다. 이 과정에서 경합이 발생하고 이로 인해 latch: cache buffers chains 이벤트를 대기하게 된다.

cache buffers chains 래치 경합이 발생하는 대표적인 경우는 다음과 같다.

  • 비효율적인 SQL
  • 핫블록(Hot Block)

[편집] 비효율적인 SQL

비효율적인 SQL문장이 cache buffers chains 래치 경합의 가장 중요한 원인이다. 동시에 여러 프로세스가 넓은 범위의 인덱스나 넓은 범위의 테이블에 대해 스캔을 수행할 경우 cache buffers chains 래치 경합이 광범위하게 발생할 수 있다.

cache buffers chains 래치 경합이 발생한 경우 경합의 원인을 정확하게 밝히는 것이 중요하다. 래치 경합이 핫블록에 의해 발생하는지 비효율적인 SQL문장에 의해 발생하는지를 판단하는 가장 중요한 근거는 SQL문장 자체이다. SQL문장 자체가 비효율적으로 작성되어 있는 것으로 판단할 수 있는 근거가 확실하다면 SQL문장을 튜닝함으로써 문제를 해결할 수 있다.

만일, SQL문장에 대한 정보가 없다면 간접적으로 핫블록에 의한 문제인지 비효율적인 SQL문장에 의한 문제인지 판단할 수 있는 방법이 있다. V$LATCH_CHILDREN 뷰에서 자식 cache buffers chains 래치에 해당하는 CHILD# 과 GETS, SLEEPS 값을 비교하여 특정 자식 래치에 사용하는 회수와 경합이 집중되는지 판단하는 것이다. 다음 명령문을 이용해서 SLEEPS 회수가 높은 자식 래치를 얻는다.

SQL>
select * from
(select child#, gets, sleeps from v$latch_children 
          where name = 'cache buffers chains'
          order by sleeps desc
) where rownum <= 20

만일 특정 자식 래치의 GETS, SLEEPS 값이 다른 자식 래치에 비해서 비정상적으로 높다면 해당 래치가 관장하는 체인에 핫블록이 있는 것으로 추측할 수 있다. 위의 테스트를 수행한 후의 결과는 다음과 같은데 특정 래치에 대한 편중 현상이 보이지 않으므로 핫블록에 의한 문제는 없다고 판단할 수 있다.

    CHILD#       GETS     SLEEPS
---------- ---------- ----------
       329      81160         78
       940      79773         74
       232      62792         69
       791      99123         68
       905      99185         68
       408      80687         65
       259     101793        62
       611      82187         62
       466      99870         60
       839      79744         60
       ...

핫블록 여부를 판단하는 또 다른 방법은 V$SESSION_WAIT 뷰로부터 래치의 주소를 얻어서 비교하는 것이다. cache buffers chains 래치의 경우 V$SESSION_WAIT.P1RAW가 자식 래치의 주소에 해당한다. 만일 V$SESSION_WAIT 뷰로부터 얻은 래치의 주소가 과다하게 중복해서 나타난다면 해당 래치에 대한 편중이 생긴다는 의미이며, 이 경우 핫블록에 의한 경합으로 해석할 수 있다.

[편집] 핫블록(Hot Block)

SQL 문장이 적절히 튜닝되었음에도 불구하고 cache buffers chains 래치의 경합이 해결이 되지 않는 경우가 있다. SQL 문의 작동방식이 소수의 특정 블록을 계속해서 스캔하는 형태로 작성되었다면, 여러 세션이 동시에 이 SQL 문을 수행하는 경우 핫블록에 의한 cache buffers chains 래치 경합이 발생한다.

V$LATCH_CHILDREN 뷰를 통해 특정 자식 래치 사용이 편중되어 있는지 확인해 보면 핫블록에 의한 래치 경합인지를 간접적으로 판단할 수 있다. 또는, V$SESSION_WAIT 뷰의 P1RAW 컬럼값을 캡쳐해서 반복적으로 관찰되는 값을 래치 주소로 이용해도 된다.

SQL> 
select * from
(select addr, child#, gets, sleeps from v$latch_children 
        where name = 'cache buffers chains'
order by sleeps desc
) where rownum <= 20
;

ADDR                 CHILD#       GETS     SLEEPS
---------------- ---------- ---------- ----------
C0000000CDFF24F0        569   10500275      11298  <-- 래치 사용 집중
C0000000CE3ADDF0        827    5250508       8085
C0000000CDF18A98        178    5250192       4781
C0000000CDEDB6E8         68       3786             17
C0000000CE3CBEE0        881       2121              8
C0000000CE359430        675       1768               1
C0000000CDEB6230           1        235               0
C0000000CDEB6B18           2        171               0
C0000000CDEB7400           3        390               0
C0000000CDEB7CE8          4        192               0
C0000000CDEB85D0          5        151               0
...

위의 결과에서 보면 child# 569, 827, 178 세 개의 자식 래치가 집중적으로 사용되고 있으며 이에 의해 래치 경합이 발생한 것을 확인할 수 있다. X$BH 뷰를 이용하면 정확하게 어떤 블록들이 핫블록인지 확인할 수 있다.

SQL> select hladdr, obj,
(select object_name from dba_objects where
     (data_object_id is null and object_id = x.obj) or
      data_object_id = x.obj and rownum = 1) as object_name,
       dbarfil, dbablk, tch from x$bh x
where hladdr in 
    ('C0000000CDFF24F0', 'C0000000CE3ADDF0', 'C0000000CDF18A98')
order by hladdr, obj;

HLADDR                         OBJ    OBJECT_NAME    DBARFIL     DBABLK   TCH
------------------------ ---------- ------------------ ------------- ------------- ------
C0000000CDF18A98         57          OBJAUTH$               1         43911       1
C0000000CDF18A98         73           IDL_UB1$               1         27025       1
C0000000CDF18A98        181 C_TOID_VERSION#          1         26792       1
C0000000CDF18A98        181 C_TOID_VERSION#          1         14244       1
…
C0000000CDF18A98      55236  CBC_TEST_IDX             4          45919   130
…
C0000000CDFF24F0      55236   CBC_TEST_IDX             4         45918    130
C0000000CE3ADDF0            2                  IND$             1           7933        1
C0000000CE3ADDF0            2                  IND$             1          60455       9
C0000000CE3ADDF0          18                  OBJ$             1          29623       1
...
C0000000CE3ADDF0     55236   CBC_TEST_IDX            4              100    130

X$BH 뷰로부터 1) 사용자 객체(Table, Index)에 해당하며, 2) 접촉 회수(Touch Count)가 높은 블록을 기준으로 핫블록을 추출할 수 있다. 위의 조회결과를 보면 CBC_TEST_IDX 인덱스의 45918, 45919, 100 블록에서 대부분의 경합이 발생하는 것을 확인할 수 있다.

[편집] Parameter & Wait Time

[편집] Wait Parameters

latch free 대기이벤트와 동일하다.

[편집] Wait Time

latch free 대기이벤트와 동일하다.

[편집] Check Point & Solution

[편집] 비효율적인 SQL 문을 튜닝한다.

비효율적인 SQL 문장을 튜닝해서 Logical Reads를 줄이면 자연스럽게 버퍼 캐시에 대한 액세스가 줄어들고 그만큼 cache buffers chains 래치 경합도 감소한다.

[편집] 핫블록을 분산한다.

핫블록에 의한 cache buffers chains 래치 경합인 경우에는 핫블록을 분산함으로써 경합을 감소시킬 수 있다. 핫블록을 분산시키는 방법은 다음과 같다.

  • PCTFREE를 높게 주거나 작은 크기의 블록을 사용함으로써 블록 경합을 줄인다. PCTFREE를 높게 주는 것과 작은 크기의 블록을 사용하는 것은 하나의 블록에 포함되는 로우수를 줄임으로써 블록 경합을 피한다는 점에서 기본적으로 동일한 방법이다. 이 방법은 확실히 블록 경합을 줄이는 효과가 있지만 그 만큼 관리해야 할 블록수가 늘어남으로써 다른 사이드 이펙트를 초래할 수 있다. 가령 블록수가 늘어남으로써 동일한 쿼리가 훨씬 더 많은 블록을 스캔해야 하기 때문에 성능 저하 현상이 생기게 된다. 즉 핫블록에 의한 래치 경합은 줄어들지만, 늘어난 스캔 회수만큼 다시 래치 경합이 증가할 수도 있다. 따라서 테스트에 의한 검증없이 적용하는 경우 일반적인 가이드와는 전혀 다른 결과를 낳을 수도 있다. 경합 해소를 위한 일반적인 가이드를 그대로 따르는 것은 때로는 위험할 수 있기 때문에 반드시 실제 데이터를 이용해 테스트를 수행하는 것이 바람직하다.
  • 파티셔닝(Partitioning) 기법을 사용해서 로우가 물리적으로 다른 블록으로 들어가게끔 한다. 이 기법을 사용하면 문제가 되는 로우들이 자연스럽게 물리적으로 다른 블록에 분산시킴으로써 래치 경합을 피할 수 있다. 하지만, 테이블에 대해서 이 방법을 적용할 경우에는 인덱스의 클러스터링 팩터(Clustering Factor)를 악화시킬 수 있으며, 이로 인해 인덱스범위스캔에 의한 데이터 스캔 속도가 저하될 수도 있다. 따라서 파티셔닝을 적용할 때도 사이드 이펙트(Side-effect)를 충분히 고려해야 한다.
  • 문제가 되는 블록의 로우들에 대해서만 삭제 후 재삽입 작업을 한다. 이 방법은 테이블에 대해서만 가능하다. 문제가 되는 블록들과 해당 블록에 포함된 로우 들의 ROWID를 정확하게 알 수 있다면 해당 로우를 삭제한 후 재삽입해서 각 로우가 다른 블록에 흩어지게 할 수 있다. 블록 덤프와 DBMS_ROWID 패키지를 이용하면 핫블록에 속한 ROWID를 알 수 있다. 이 방법은 테이블 속성을 변경하지 않는 가장 이상적인 방법이라고 할 수 있다. 하지만 핫블록이 고정되어 있지 않고 SQL문의 조건(Where …)에 따라 매번 바뀐다면 적용할 수 없다. 또한 인덱스에 대해서는 이 방법을 사용할 수 없다.

테이블에서의 cache buffers chains 래치 경합은 해결하기가 비교적 쉬운 편이다. 로우를 분산시킬 수 있는 방법이 매우 다양하기 때문이다. 하지만, 인덱스에서의 경합 문제는 상당히 까다롭다. 정렬된 상태로 저장된다는 인덱스의 고유 특성 때문에 임의의 블록으로 분산시키는 것이 불가능한 경우가 있기 때문이다. 이 경우에는 PCTFREE를 높게 주거나 작은 크기의 블록을 사용하는 방식을 사용하는 것 외에는 뾰족한 대책이 없다. 하지만 앞서 설명한 것처럼, 이 경우에 블록의 개수가 늘어나게 되고 이로 인해 오히려 래치 경합이 줄어들지 않는 경우도 있으므로 적용 시에 유의해야 한다.

[편집] Event Tip

[편집] 버퍼 캐시 구조

오라클은 물리적인 I/O를 최소화하기 위해 최근에 사용된 블록에 대한 정보를 메모리의 일정 영역에 보관한다. 이 메모리 영역을 버퍼 캐시라고 부른다. 버퍼 캐시는 Shared Pool, 리두 버퍼(Redo Buffer)와 함께 SGA를 이루는 가장 중요한 메모리 영역 중 하나다. 아래 명령을 이용해 현재 인스턴스의 버퍼 캐시(Buffer cache)의 크기를 알 수 있다.

SQL> show sga
Total System Global Area  314572800 bytes
Fixed Size                   788692 bytes
Variable Size             144963372 bytes
Database Buffers          163577856 bytes
Redo Buffers                5242880 bytes

Database Buffers에 해당하는 값이 현재 인스턴스의 버퍼 캐시의 크기이다.

오라클은 버퍼 캐시를 효과적으로 관리하기 위해 해시 체인(Hash chain) 구조를 사용한다. 해시 체인은 Shared Pool 내에 존재하며 오라클의 전형적인 메모리 구조 관리기법인 버킷(Bucket) -> 체인(Chain) -> 헤더(Header) 의 구조를 사용한다. 이 구조는 아래 그림에 표현되어 있다.

그림 : Mycachebufferchain.jpg

그림 오라클 8i이상에서의 버퍼 캐시 구조도

해시 체인 구조의 시작점은 해시 테이블(Hash table)이다. 해시 테이블은 여러 개의 해시 버킷(Hash bucket)으로 이루어져 있다. 하나의 해시 버킷은 해시함수 결과와 매칭된다. 오라클은 블록의 주소(DBA: Data Block Address. File#와 Block#으로 이루어져 있음)와 블록 클래스에 대해 간단한 해시 함수를 적용한 결과를 이용해 해시 버킷을 찾아간다. 해시 버킷에는 같은 해시값을 갖는 버퍼 헤더(Buffer Header)들이 체인 형태로 걸려 있다. 버퍼 헤더는 버퍼(Buffer)에 대한 메타정보를 가지고 있으며, 버퍼 메모리 영역의 실제 버퍼에 대한 포인터 값을 가지고 있다. 해시 체인 구조는 Shared Pool 영역에 존재하며, 실제 버퍼에 대한 정보들은 버퍼 캐시 영역에 존재한다는 사실을 명심하자.

해시 체인 구조는 cache buffers chains 래치를 이용해 보호된다. 특정 블록을 스캔하고자 하는 프로세스는 반드시 해당 블록이 위치한 해시 체인을 관리하는 cache buffers chains 래치를 획득해야 한다. 기본적으로 한번에 하나의 프로세스만이 하나의 cache buffers chains 래치를 획득할 수 있으며 하나의 cache buffers chains 래치가 여러 개의 해시 체인을 관리한다. 따라서, 동시에 많은 수의 프로세스가 버퍼 캐시를 탐색할 경우 cache buffers chains 래치를 획득하는 과정에서 경합이 발생하며, 이 과정에서 latch: cache buffers chains 이벤트를 대기한다. 오라클 9i 부터는 읽기 전용의 작업에 한해서 cache buffers chains 래치를 Shared 모드로 획득한다. 따라서 동시에 읽기 작업을 수행하는 프로세스간에는 cache buffers chains 래치를 공유할 수 있다. 하지만 버퍼에 대해 Buffer Lock을 획득하거나 해제할 때 cache buffers chains 래치를 Exclusive하게 획득해야 하기 때문에 읽기 작업만 수행하는 경우에도 여전히 cache buffers chains 래치 경합은 발생한다.

다음과 같은 명령문으로 cache buffers chains 래치의 개수를 구할 수 있다.

SQL> select count(*) from v$latch_children where name = 
        'cache buffers chains';
  COUNT(*)
  ----------
       1024

또는 _DB_BLOCK_HASH_LATCHES 히든 파라미터값을 조회해도 같은 결과를 얻을 수 있다. 해시 버킷의 수는 _DB_BLOCK_HASH_BUCKETS 히든 파라미터값을 이용해 조회 가능하다.

[편집] Working Set

오라클은 버퍼 캐시를 효율적으로 사용하기 위해 두 종류의 LRU(Least Recently Used) 리스트를 사용한다. LRU 리스트는 가장 최근에 사용되거나 미사용된 버퍼들의 리스트로 프리(Free. 미사용) 버퍼, 사용 중이거나 사용된 버퍼, 아직 LRUW 리스트(Dirty List)로 옮겨지지 않은 더티(Dirty. 변경된) 버퍼 등을 포함한다. 일부 문서에서는 LRU 리스트를 대체 리스트(Replacement List)라고 부른다. LRUW 리스트는 아직 디스크에 기록되지 않은 변경된(Dirty한) 버퍼들의 리스트를 관리한다. 버퍼 캐시의 모든 버퍼들은 반드시 LRU 리스트 또는 LRUW 리스트 둘 중의 하나에 속한다. LRUW 리스트는 더티 리스트(Dirty List), 또는 기록 리스트(Write List)라고도 부른다.

오라클은 리스트 스캔의 효율성을 위해 LRU 리스트나 LRUW 리스트를 다시 메인 리스트(Main List)와 보조 리스트(Auxiliary List)로 나누어 관리한다. 이를 정리하면 다음과 같다.

LRU 리스트(대체 리스트)

  • 메인 리스트 : 사용된 버퍼들의 리스트. 핫 영역과 콜드 영역으로 구분 관리된다.
  • 보조 리스트 : 프리 버퍼들의 리스트. 더 정확하게 표현하면, 미 사용된 버퍼들이나, DBWR에 의해 기록된 버퍼들의 리스트

LRUW 리스트(기록 리스트)

  • 메인 리스트 : 변경된 버퍼들의 리스트
  • 보조 리스트 : 현재 DBWR에 의해 기록중인 버퍼들의 리스트

오라클은 프리 버퍼 탐색 시, 우선 LRU 리스트의 보조 리스트에서 프리 버퍼를 찾는다. 보조 리스트의 버퍼가 모두 사용된 경우에는, 메인 리스트의 콜드 영역에서 프리 버퍼를 찾는다. 인스턴스가 최초로 구동된 때는 모든 버퍼들은 보조 리스트에서 관리된다. 또한 변경된 버퍼들이 DBWR에 의해 기록된 후에는 다시 프리 버퍼로 바뀌며, LRU 리스트의 보조 리스트에 추가된다.

LRU 리스트 와 LRUW 리스트는 항상 짝(Pair)으로 존재하며, 이 짝을 Working Set이라고 부른다(즉 Working Set = LRU + LRUW). 오라클은 복수 개의 Working Set을 사용한다. 하나의 Working Set을 하나의 cache buffers lru chain 래치가 관리한다. LRU 리스트나 LRUW 리스트를 탐색하고자 하는 프로세스는 반드시 cache buffers lru chain 래치를 획득해야 한다. 따라서 동시에 많은 프로세스가 LRU 리스트나 LRUW 리스트를 탐색하고자 할 경우에 cache buffers lru chain 래치를 획득하기 위해 경쟁하게 되며 이 과정에서 latch: cache buffers lru chain 이벤트를 대기한다.

_DB_BLOCK_LRU_LATCHES 히든 파라미터의 값을 조회하거나, 다음 명령문을 이용해 cache buffers lru chain 래치의 최대 개수를 구할 수 있다.

SQL> select count(*) from v$latch_children where name = 'cache buffers lru chain'; 
 COUNT(*)
 ----------
         16

하지만 위의 래치를 다 사용하는 것은 아니다. 오라클에는 다양한 종류의 버퍼 풀이 존재하며 각 버퍼 풀들이 이들 래치를 골고루 사용한다. 첫째, 버퍼는 크게 Default 버퍼 풀, Keep 버퍼 풀, Recycle 버퍼 풀로 나누어 진다. 둘째, Default 버퍼 풀은 다시 블록 크기 별로 표준블록사이즈, 2K, 4K, 8K, 16K, 32K 버퍼 풀로 나누어 진다. 개개의 버퍼 풀은 각각 독립적인 cache buffers lru chain 래치를 사용한다. 따라서 래치의 최소 개수는 8개가 된다. 다음 명령문을 사용하면 어떤 래치가 어떤 종류의 버퍼에 대해 사용 중인지를 확인할 수 있다.

SQL> 
-- x$kcbwds=Working Set, x$kcbwbpd=Buffer pool, v$latch_children=Latch
select d.blk_size, c.child#, p.bp_name, c.gets, c.sleeps
from x$kcbwds d, v$latch_children c, x$kcbwbpd p
where
 d.set_latch = c.addr
 and d.set_id between p.bp_lo_sid and p.bp_hi_sid
order by c.child#
;

  BLK_SIZE     CHILD# BP_NAME                    GETS     SLEEPS
---------- ---------- -------------------- ---------- ----------
      8192          1 KEEP                            42         0
      8192          2 KEEP                            42         0
      8192          3 RECYCLE                      42         0
      8192          4 RECYCLE                      42         0
      8192          5 DEFAULT                   2337         0     <-- 실제 사용중
      8192          6 DEFAULT                   2322         0     <-- 실제 사용중
      2048          7 DEFAULT                      33          0
      2048          8 DEFAULT                      33          0
      4096          9 DEFAULT                      32          0
      4096         10 DEFAULT                     32          0
      8192         11 DEFAULT                     32          0
      8192         12 DEFAULT                     32          0
     16384         13 DEFAULT                    32          0
     16384         14 DEFAULT                    32          0
     32768         15 DEFAULT                    32          0
     32768         16 DEFAULT                    32          0


위의 결과를 해석하면 Keep 버퍼 풀에 대해 2개, Recycle 버퍼 풀에 대해 2개, 그리고 Default 버퍼 풀에 대해 블록 크기 별로 각각 2개씩 래치를 사용하는 것을 알 수 있다. 만일 Default 버퍼 풀에 8K 표준 크기의 버퍼 풀만 사용한다면 2개의 lru 래치 만을 사용하게 될 것이다. 최대 16개의 래치 개수는 CPU 개수로부터 유래된 것이다. 오라클은 DBWR의 개수가 4보다 작으면 4 * CPU_COUNT 만큼 lru 래치를 생성하고, DBWR의 개수가 4이상이면 DB_WRITER_PROCESSES * CPU_COUNT 만큼 lru 래치를 생성한다. 필자의 시스템에서는 CPU 개수가 네 개이므로 16개의 래치가 생성되었고 그 중 실질적으로 사용되고 있는 것은 8K 버퍼 풀에 할당된 두 개의 래치임을 알 수 있다. 단, 앞서 언급한 것처럼 버퍼 풀의 최소 개수가 8개이기 때문에 lru 래치의 최소 개수도 8개임에 유의하자.

[편집] 버퍼 캐시 LRU 리스트의 관리

서버 프로세스가 스캔하는 모든 버퍼들이 LRU 리스트에 등록되기 때문에 LRU 리스트를 효율적으로 관리하는 것이 매우 중요하다. 특히 불필요하게 많은 량의 블록을 스캔하는 프로세스에 의해 중요한 버퍼들이 버퍼 캐시에서 밀려나는 것을 최소화할 수 있어야 한다. 오라클은 8i 이후의 버전부터 LRU 리스트를 효율적으로 관리하기 위해 Touch count에 기반한 LRU 알고리즘을 사용한다. 이 알고리즘은 LRU 리스트의 메인 리스트를 관리하는데 사용된다. Touch count 기반의 LRU 알고리즘을 그림으로 표현하면 아래 그림과 같다.

그림 : TouchCount_LRUList.jpg

Touch count 기반의 LRU 알고리즘은 다음과 같은 방식으로 작동한다.

  1. LRU 리스트의 메인 리스트는 크게 핫 영역(Hot Region)과 콜드 영역(Cold Region)으로 나누어진다. 자주 사용되는 블록은 핫 영역에 머무르며, 사용빈도가 낮은 블록은 콜드 영역에 머무른다. 오라클은 개별 버퍼마다 Touch count(접촉 회수)를 관리하며, 프로세스에 의해 스캔이 이루어질 때마다 Touch count를 1씩 증가시킨다.
  2. 프리 버퍼를 찾을 때는 우선 LRU 리스트의 보조 리스트에서 미사용된 버퍼를 찾는다. 만일 보조 리스트가 비어 있다면, 메인 리스트의 콜드 영역의 꼬리에서부터 프리 버퍼를 찾는다. 메인 리스트의 꼬리에 있으면서 Touch count가 1이하인 버퍼가 프리 버퍼로 사용된다. 프리 버퍼를 찾는 과정에서 Touch count가 2 이상인 블록을 만나면 핫 영역의 머리(Head of Hot Region)로 옮기고 해당 버퍼의 Touch count를 0으로 초기화시킨다. 핫 영역으로 옮기는 기준이 되는 값은 _DB_AGING_HOT_CRITERIA 히든 파라미터이며 기본값이 2이다.
  3. 싱글 블록 I/O에 의해 읽혀진 블록은 Mid-point에 삽입되며 Touch count는 1의 값을 지닌다. Mid-point가 가리키는 위치는 콜드 영역의 머리(Head of Cold Region)이다. 싱글 블록 I/O에 읽혀진 블록은 콜드 영역의 머리에 위치함으로써 버퍼 캐시에 머무를 확률이 높아진다.
  4. 멀티 블록 I/O에 의해 읽혀진 블록들은 Mid-point에 삽입된 후 콜드 영역의 제일 뒤(Tail of Cold Region)으로 옮겨진다. 풀테이블스캔(FTS)이나 인덱스풀스캔으로 읽힌 블록들은 콜드 영역의 꼬리에 위치함으로써 버퍼 캐시에 머무를 확률이 낮아진다.
  5. Keep 버퍼 풀과 Recycle 버퍼 풀은 Default 풀과는 달리 영역의 구분이 불필요하므로 핫 영역을 가지지 않는다. Recycle 버퍼 풀은 핫 영역을 가지지 않는다는 점을 제외하면 Default 버퍼 풀과 완전히 동일한 방식으로 작동한다. 하지만 Keep 버퍼 풀의 경우에는 FTS로 읽히는 작은 크기의 테이블을 메모리에 상주시키기 위해 고안된 공간이기 때문에 멀티 블록 I/O로 읽은 블록들을 싱글 블록 I/O로 읽은 블록과 동일하게 콜드 영역의 제일 앞에 위치시키도록 구현되었다.

[편집] 버퍼 탐색 과정

오라클은 해시 체인과 LRU, LRUW 리스트를 적절히 사용해서 사용자가 요청한 블록을 버퍼 캐시로 위치시킨다. 그 절차 및 기법을 시간 순으로 정리하면 다음과 같다.

  1. 사용자가 요청한 블록의 DBA와 클래스에 대해 해시 함수를 이용해서 해시 값을 생성하고 해시 값에 해당하는 해시 버킷을 찾는다.
  2. 해시 버킷을 보호하는 cache buffers chains 래치를 획득한다. 읽기 작업이라면 Shared 모드로, 변경 작업이라면 Exclusive 모드로 래치를 획득한다. 만일 이 과정에서 경합이 발생하면 latch: cache buffers chains 이벤트를 대기한다. 해시 버킷에 딸려있는 체인을 탐색해서 블록에 해당하는 버퍼 헤더가 존재하는지 확인한다. 버퍼 헤더가 이미 존재하고 해당 블록이 버퍼 캐시에 올라와 있는 상태라면 해당 버퍼에 대해 Buffer Lock을 Shared 모드나 Exclusive 모드로 획득하고 원하는 작업을 수행한다. 일반적으로 Buffer Lock을 획득하는 과정에서 경합이 발생하면 buffer busy waits 이벤트를 대기하게 된다. DBWR에 의해 기록중인 버퍼에 대해 Buffer Lock을 획득하는 과정에서 경합이 발생하는 경우에는 write complete waits 이벤트를 대기한다. cache buffers chains 래치를 획득한 후 해시 체인을 탐색하고 버퍼를 사용하기 위해 Buffer Lock을 획득한 후 버퍼를 읽는 일련의 작업을 “Logical Reads”라고 부른다. Logical Reads가 발생한 블록 수만큼 session logical reads 통계 값이 증가한다. 만일 Logical Reads 작업이 일관된 모드의 읽기(Consistent read) 작업이라면 consistent gets 통계 값이 증가하고, 현재 모드의 읽기(Current read) 작업이라면 db block gets 통계 값이 증가한다. 따라서 session logical reads 통계 값은 consistent gets 통계 값과 db block gets 통계 값의 합과 일치한다.
  3. 버퍼 캐시에 블록이 존재하지 않으면 우선 Working Set을 관리하는 cache buffers lru chain 래치를 획득한다. 이 과정에서 경합이 발생하면 latch: cache buffers lru chain 이벤트를 대기한다. 래치를 획득한 후 LRU 리스트의 보조 리스트에서 프리 버퍼를 찾는다. 보조 리스트가 비었다면, 메인 리스트에서 가장 덜 사용된 순서로 프리 버퍼를 찾는다. 이 과정에서 더티 버퍼가 발견되면 LRUW 리스트로 이동시킨다. 프리 버퍼를 찾게 되면 해당 버퍼에 대해 Buffer Lock을 Exclusive하게 획득하고 데이터 파일로부터 블록을 해당 버퍼로 읽어 들인다. 이때 Buffer Lock을 획득하는 과정에서 경합이 발생하면 read by other session 이벤트를 대기한다. 데이터 파일로부터 물리적으로 블록을 읽어 들이는 일련의 작업을 Physical Reads”라고 부른다. Physical Reads가 발생한 블록 수만큼 physical reads 통계 값이 증가한다. physical reads 통계 값은 direct path I/O 작업에서도 증가하기 때문에, 버퍼 캐시를 경유한 정확한 Physical Reads 값은 physical reads 통계 값에서 physical reads direct, physical reads direct(lob) 통계 값을 빼면 된다.
  4. LRU 리스트에서 프리 버퍼를 찾을 때 _DB_BLOCK_SCAN_MAX_PCT(기본값은 40) 파라미터의 값만큼 스캔을 하고도 프리 버퍼를 찾지 못하면 서버 프로세스는 LRU 리스트의 스캔을 멈춘다. 서버 프로세스는 DBWR에게 더티 버퍼를 파일에 기록하고 프리 버퍼를 확보할 것을 요청한다. DBWR에 의해 프리 버퍼가 확보될 때까지 서버 프로세스는 free buffer waits 이벤트를 대기한다. 요청을 받은 DBWR은 DBWR make free request 통계 값을 증가시키고, cache buffers lru chain 래치를 획득한 후 LRUW 리스트를 콜드 영역의 꼬리에서부터 탐색한다. 디스크에 기록할 버퍼를 찾게 되면 Buffer Lock을 획득한 후 버퍼를 디스크에 기록한다. 디스크에 기록된 버퍼는 프리 버퍼로 변경되고 LRU 리스트로 옮겨진다. DBWR이 LRUW 리스트를 탐색할 때마다 DBWR lru scans 통계 값과 DBWR buffers scanned 통계 값이 증가한다.

[편집] Analysis Case

[편집] 1. 인덱스 튜닝에 의한 latch: cache buffers chains 대기 감소

latch: cache buffers chains 이벤트 발생 시나리오는 다음과 같다.

  • t_cache_buffers_chains_latch(type,name,id) 테이블에는 16만건의 데이터가 입력되어 있으며, 이중 type=4, name=’KIM’을 만족하는 데이터는 15만건이다.
  • idx_cache_buffers_chains_latch 인덱스는 type, name 두개의 컬럼으로 구성되어 있다.
  • 10개의 세션이 동시에 (type=4, name=’KIM’, id=4)을 만족하는 데이터의 개수를 구하는 SQL을 idx_cache_buffers_chains_latch 인덱스를 사용하여 수행된다.
  • 세션들은 수행중 내내 latch: cache buffers chains 이벤트를 대기한다.

위의 시나리오를 그림으로 표현하면 아래 그림 1과 같다. 그림 : Latch_mycache_buffer_chains.jpg 그림 latch: cache buffers chains 이벤트 발생 시나리오

동시에 여러 프로세스가 위의 쿼리를 실행하는 과정을 모니터링한 결과는 아래 표와 같다. latch: cache buffers chains 이벤트 대기가 가장 심각하게 발생함을 알 수 있다.

표 모니터링 결과

실행 결과 SQL> @report

---- Report Scenario No. 2 -------------------------
scenario_name : cache_buffers_chains_latch
session#  : 10
expired_type  : 1
inteval  : 30
Type=EVENT, Name=jobq slave wait, Value=50404(cs)
Type=EVENT, Name=latch: cache buffers chains, Value=3061(cs)
Type=EVENT, Name=read by other session, Value=677(cs)
Type=EVENT, Name=db file sequential read, Value=537(cs)
Type=EVENT, Name=events in waitclass Other, Value=534(cs)
Type=EVENT, Name=library cache pin, Value=73(cs)
Type=EVENT, Name=enq: TX - row lock contention, Value=63(cs)
Type=EVENT, Name=buffer busy waits, Value=15(cs)
Type=EVENT, Name=latch: library cache, Value=0(cs)
Type=EVENT, Name=latch: shared pool, Value=0(cs)
Type=EVENT, Name=cursor: mutex X, Value=0(cs)
Type=STATS, Name=session pga memory max, Value=12955464
Type=STATS, Name=session logical reads, Value=7205239
Type=STATS, Name=redo size, Value=25088
Type=STATS, Name=execute count, Value=513
Type=STATS, Name=physical reads, Value=356
Type=STATS, Name=parse count (total), Value=229
Type=STATS, Name=sorts (memory), Value=110
Type=STATS, Name=parse time elapsed, Value=92
Type=STATS, Name=redo entries, Value=87
Type=STATS, Name=parse count (hard), Value=62
Type=STATS, Name=session cursor cache hits, Value=53
Type=STATS, Name=user commits, Value=20
Type=STATS, Name=sorts (disk), Value=0
Type=TIME, Name=DB time, Value=29893(cs)
Type=TIME, Name=sql execute elapsed time, Value=29808(cs)
Type=TIME, Name=parse time elapsed, Value=103(cs)
Type=TIME, Name=hard parse elapsed time, Value=23(cs)

RealTime Client의 Active Session List는 아래 그림 2와 같다. 대부분의 액티브 세션들이 latch: cache buffers chains 이벤트를 대기하고 있는 것을 확인할 수 있다.

그림 : SM_ORA10GR2.jpg 그림 RealTime Client – Active Session List

위와 같은 같은 상황에서 latch: cache buffers chains 이벤트 대기가 발생하는 이유는 다음과 같다.

  • idx_cache_buffers_chains 인덱스를 사용하여 데이터를 검색하면 16만건 중 15만건의 데이터가 조건을 만족하므로 이 15만건에 대해 다시 테이블 액세스가 발생하게 되어 결과적으로 넓은 범위의 블록에 대한 랜덤 엑세스(Random Access)가 반복적으로 발생하게 된다.
  • Cache Buffer 는 검색성능을 향상시키기 위해 해시체인(Hash Chains)으로 관리되어지는데 이 체인을 검색하기위해서는 반드시 래치를 획득하여야만 한다. 하지만 10개의 세션이 동시에 래치를 획득하기 위해 경합이 발생하게 되므로 latch: cache buffers chains 이벤트에 대한 대기가 불가피하게 된다.

SQL의 검색조건중 id컬럼은 선택도가 양호하므로 이것을 인덱스 사용시 이용할 수 있도록 한다.

  • 기존의 idx_cache_buffers_chains에 id컬럼을 추가한다.
  • 15만회에 걸쳐 테이블검색을 하던 것을 1회검색으로 원하는 결과를 얻게 되므로 경합은 현저히 줄어들게 된다.

그림 : Scenario_cache_chain.jpg 그림 latch: cache buffers chains 이벤트 대기 개선 시나리오

-- 기존의 idx_cache_buffers_chains 인덱스 삭제
DROP INDEX idx_cache_buffers_chains;

-- 인덱스에 id컬럼을 추가하여 새로 생성
CREATE INDEX idx_cache_buffers_chains 
ON t_cache_buffers_chains_latch(type,name,id);

성능 개선 후의 모니터링 결과는 아래 표와 같다. 표 2에서 latch: cache buffers chains 이벤트의 대기 시간이 1133(cs)로, 성능 개선 전인 3061(cs)이었던 것에 비하면 3배 정도 개선효과가 있는것을 확인할 수 있다.

표 자체 모니터링 결과

실행결과 SQL> @report

---- Report Scenario No. 3 -------------------------
scenario_name : cache_buffers_chains_latch
session#  : 10
expired_type  : 1
inteval  : 30
Type=EVENT, Name=jobq slave wait, Value=4994(cs)
Type=EVENT, Name=latch: cache buffers chains, Value=1133(cs)
Type=EVENT, Name=latch: library cache, Value=362(cs)
Type=EVENT, Name=enq: TX - row lock contention, Value=284(cs)
Type=EVENT, Name=latch: library cache pin, Value=135(cs)
Type=EVENT, Name=library cache load lock, Value=75(cs)
Type=EVENT, Name=library cache pin, Value=32(cs)
Type=EVENT, Name=events in waitclass Other, Value=18(cs)
Type=EVENT, Name=db file sequential read, Value=2(cs)
Type=EVENT, Name=cursor: mutex S, Value=0(cs)
Type=EVENT, Name=latch: In memory undo latch, Value=0(cs)
Type=STATS, Name=session pga memory max, Value=10530632
Type=STATS, Name=session logical reads, Value=3745047
Type=STATS, Name=execute count, Value=748866
Type=STATS, Name=redo size, Value=22120
Type=STATS, Name=parse count (total), Value=296
Type=STATS, Name=sorts (memory), Value=159
Type=STATS, Name=session cursor cache hits, Value=131
Type=STATS, Name=parse count (hard), Value=67
Type=STATS, Name=parse time elapsed, Value=57
Type=STATS, Name=redo entries, Value=53
Type=STATS, Name=user commits, Value=20
Type=STATS, Name=physical reads, Value=5
Type=STATS, Name=sorts (disk), Value=0
Type=TIME, Name=DB time, Value=26548(cs)
Type=TIME, Name=sql execute elapsed time, Value=26534(cs)
Type=TIME, Name=parse time elapsed, Value=85(cs)
Type=TIME, Name=hard parse elapsed time, Value=36(cs)


[편집] 2. 과도한 Logical Read로 인한 cache buffer chain latch 발생 분석 사례

동시사용자가 많은OLTP 및 WEB환경에서, 부적절한 인덱스 사용으로 인한 과도한 I/O발생은 성능상의 심각한 문제를 야기하는 경우가 많다. Oracle DBMS의 성능진단/분석 툴인 MaxGauge(맥스게이지)를 활용하여, 부적절한 인덱스 사용으로 인한 과도한 I/O발생이 야기시키는 성능저하 문제의 원인을 규명해 보고자 한다.

[편집] 성능저하구간의 확인

성능문제가 발생한 인스턴스에서 수집된 가동이력 로그로부터 일간 추이그래프를 확인해 보면,「CPU 사용률」은 높지만 execute count가 적은 DB Management시간대(01시30분~05시00분)를 제외하고 「CPU 사용률], [Active session count], [Wait]가 동일한 추이로 변화하고 있음을 감지할 수 있다.

■ CPU사용률의 추이그래프 그림 : Case10_1.jpg

■ Active Session수의 추이그래프 그림 : Case10_2.jpg

■ Wait Events의 추이그래프(Wait Time or Waits) 그림 : Case10_3.jpg

■ Execution Count의 추이그래프 그림 : Case10_4.jpg

[편집] Wait Events의 검출 및 분석

Active Session의 급증으로 인한 성능저하(Performance Slow-Down)의 원인을 규명하기 위해, 문제시점(10시17분)의 Wait Events의 발생내용을 확인해 본다. 그림 : Case10_5.jpg 「Value」 탭에서 동 시점의 Top Wait Event를 확인한 결과, Idle Event(= SQL*Net message from client)를 제외한 Top Wait Event는 latch free임이 확인 된다.

그림 : Case10_6.jpg Active Session의 급증에 대한 Latch free 대기이벤트의 연관성을 규정하기 위해, 대기이벤트와의 발생패턴을 비교해 본 결과, Active Session의 발생 추이와 상당히 유사하고, 문제시점에 발생한 Wait Events(Wait Time)의 약 53.4%(전체 109.89초 중에서, 58.69초를 점유 함)를 차지하고 있는 점에서, Active Session의 급증은 latch free 대기이벤트의 급격한 발생과 연관이 있음을 추측할 수 있다.

그림 : Case10_7.jpg 실제로, 같은 시점의 상세데이터를 표시하는 「세션 Grid」 화면에서도, latch free가 Top Wait Event이며, 그 중에서도 latch free(cache buffer chain) 대기 이벤트가 많이 발생해 있음을 확인할 수 있다.

[편집] Wait Event(Latch Free)발생원인의 조사

latch free대기이벤트의 발생원인에는 여러 가지가 있으나, 일반적으로 latch free (cache buffer chain) 대기이벤트가 발생한 경우에는 「Hot block」이 그 원인일 경우가 많다. Hot block은 table full scan보다는 index range scan에서 빈번하게 발생하며, 해결책으로는 SQL 튜닝을 통하여 Index 검색 범위를 줄여야 하며 SQL 튜닝이 불가능한 경우에는 블록 사이즈를 줄이거나 pct free 값을 증가시켜 블록당 row수를 줄여야 한다.

[편집] 세션 및 SQL의 분석을 통한 문제원인의 규명

latch free (cache buffer chain)의 대기가 많았던 21시30분~ 21시40분 사이에서, latch free (cache buffer chain)를 유발한 SQL이 동일한 패턴의 SQL로 확인된다. 그림 : Case10_8.jpg

[편집] 결론

latch free(cache buffer chain)대기이벤트의 다발에 의한 Active session의 급증 →

SQL 수행 시 비효율적인 Index Scan으로 인한 성능 저하 발생 →

Table Access 없이 Index Scan으로 수행되도록 해당 SQL의 조건절 칼럼을 Index에 모두 포함시켜 재생성 하여 해결


[편집] 3. 잘못된 인덱스 스캔으로 인한 Latch 경합

성능문제가 발생한 인스턴스에서 수집된 가동이력로그 및 실시간 모니터링을 통해 Active Session의 추이를 확인해본다. 문제 구간의 Active Session은 Cache Buffers Chains Latch 이벤트를 대기하고 있고, Active Session List의 Wait 항목에서 Latch의 주소값(ADDR)은 16321267696임을 알 수 있다.

그림 : 6_2_1.jpg

Latch 경합이 발생한 Latch의 Address를 X$bh 뷰와 조인하여 어떤 오브젝트의 블록인지 확인한다.

-- X$bh 뷰와 조인하여 블록을 확인하는 SQL문 -- 
select a.hladdr, a.file#, a.dbablk, a.tch, a.obj, b.object_name, b.object_type
from   sys.xm$bh a, dba_objects b
where  (a.obj = b.object_id or a.obj = b.data_object_id)
and    a.hladdr = '00000003CCD2C7F0'
order by 4 desc

이 중, Touch Count(TCH)가 높은 블록을 확인한다.

같은 Latch Addr 로 조회 시 여러 개의 object 결과값이 나오는 이유는 하나의 래치가 여러 개의 체인을 관리하기 때문이다. 문제의 인스턴스의 Cache Buffers Chains Latch는 1024 개이고, _DB_BLOCK_HASH_BUCKETS 파라미터는(해시 버킷의 수) 254083 개이다. 즉, 문제의 인스턴스에서 1개의 CBC 래치는 약 249 개의 체인을 관리하고 있다.

그림 : 6_2_2.jpg

ABC$123 이란 INDEX가 가장 TCH가 높으므로, Cache Buffers Chains Latch 경합의 주요 발생 블록임을 유추할 수 있다.

dba_indexes 뷰를 통해 해당 인덱스의 TABLE을 확인하고, 해당 테이블의 인덱스 구성을 확인한다.

select index_name, table_name
from dba_indexes
where index_name = 'ABC$123';

그림 : 6_2_3.jpg

ABC$123 인덱스는 ABC 테이블에 있으며, ABC 테이블은 ABC_NUM + ABC_TIM 으로 구성된 UNIQUE 인덱스와 ABCTYPE으로 구성된 인덱스를 가지고 있음. 래치 경합으로 문제가 된 인덱스는 DMLTYPE로 구성된 ABC$123 인덱스이다.

그림 : 6_2_4.jpg

경합이 발생한 세션의 SQL문의 트레이스 결과를 확인해본다.

-- SQL문 --
UPDATE ABC 
SET    version$$=version$$+1 ,
          type$$='I' 
WHERE  ABC_NUM =:b2 
AND    ABC_TIM" =:b1 
AND    ABC_TYPE='D'

그림 : 6_2_5.jpg

SQL문의 조건에 PK Index의 구성 컬럼이 있음에도 불구하고, 범위가 넓은 인덱스를 선택해 SQL문이 실행되었음을 알 수 있다. (query 부분을 통해, 수행 시 불필요하게 174427 블록을 액세스함을 알 수 있다.)

이 경우, 힌트를 적용하여 PK Index를 경유하게 되면, Cache Buffers Chains Latch 경합을 해소할 수 있다.


[편집] 4. 인덱스 컬럼 변형에 의한 Latch 대기현상

시스템의 CPU 사용율이 Logical Reads와 Physical Reads와 유사한 추이를 나타내고 있다. SQL의 수행횟수를 나타내는 Execute Count는 평균적으로 500회 정도를 유지하고 있으며, SQL의 수행횟수가 많아서 CPU를 많이 사용한 것은 아닌 것으로 추측된다. 그림 : 7_2_1.jpg

이 구간의 Active Session 추이를 확인해 보면, Latch Free 이벤트와 추이가 유사함을 알 수 있고, Cache Buffers Chains Latch를 대기하는 세션들을 발견할 수 있다. 그림 : 7_2_2.jpg

Cache Buffers Chains Latch는 SQL문을 수행 시에 넓은 처리범위로 인하여 발생한다. 또한, db file sequencial reads 이벤트의 발생 추이도 유사하므로, SQL문이 인덱스 스캔을 통해 수행하고 있으나 비효율적인 인덱스를 통해 데이터를 Access하고 있으며 이로 인해 처리범위가 과다하게 나타난 것으로 예상된다.

이 사례는 세션이 수행하고 있는 SQL문에서 distinct key의 종류가 많아서 분포도가 좋은 컬럼이 변형되어 그 컬럼의 인덱스를 경유하지 못하고 비효율적인 컬럼의 인덱스를 통해 데이터를 Access한 경우이다.

예를들면, 다음과 같다.

SELECT emp_id, emp_name, salary, emp_date, dept_id
FROM   emp
WHERE  emp_date >=:1
AND    emp_date <=:2
AND    TO_NUMBER( emp_id ) =:3
AND    emp_name like :4
AND    job_id =:5

와 같은 SQL문을 수행하는데, emp_id 컬럼에 TO_NUMBER라는 함수를 사용하여 해당 인덱스를 이용하지 못하고 emp_name의 컬럼의 인덱스를 이용해서 실행이 된 경우로 이해할 수 있다.

이 경우, 다음과 같이 변경하여야 한다.

SELECT emp_id, emp_name, salary, emp_date, dept_id
FROM   emp
WHERE  emp_date >=:1
AND    emp_date <=:2
AND    emp_id =to_char(:3)
AND    emp_name like :4
AND    job_id =:5

이와 같이, Latch: Cache buffers chains 가 발생하는 경우, 과다한 처리범위를 발생하는 SQL문을 추출하여야 하고, 처리범위를 줄이기 위해 Tuning이 필요하다.

반응형

'ORACLE > TUNING' 카테고리의 다른 글

SORT와 PGA_AGGREGATE_TARGET  (0) 2012.09.06
PGA(Program Global Area) 관리  (0) 2012.09.06
Oracle Wait Event 모니터링  (0) 2012.05.02
Chapter 9 Tuning Buffer Cache  (0) 2012.05.02
AWR report 생성 및 분석  (0) 2012.03.08
Posted by [PineTree]
ORACLE/ADMIN2012. 8. 23. 15:06
반응형

 

using-dynamic-intimate-memory-sparc-168402.pdf

 

Dynamic Intimate Shared Memory (DISM)

Dynamic Intimate Shared Memory (DISM)를 사용하여 데이터베이스가 공유 데이터 세그먼트의 크기를 동적으로 확장 또는 감소시킬 수 있습니다. 이 기능은 Intimate Shared Memory (ISM)의 잘못된 구성 문제 및 서비스 거부 안전 취약성을 제거합니다.

ISM은 대량의 잠긴 메모리 페이지로 구성된 공유 메모리 세그먼트입니다. ISM 잠긴 페이지 수는 일정하거나 불변합니다. 동적 ISM (DISM)은 페이지 가능한 ISM 공유 메모리로서 잠긴 페이지의 수가 다양합니다(변경 가능). 따라서 DISM은 동적 재구성 시 시스템에 물리적 메모리를 해제나 추가할 수 있도록 지원합니다. DISM 크기는 사용 가능한 물리적 메모리에 디스크 스왑을 더한 크기입니다.

shmop(2) 설명서 페이지를 참조하십시오.


주 –

Solaris 9 9/02 갱신 릴리스에서는 DISM에 대해 대형 페이지를 지원합니다. 대형 페이지 지원에 대한 설명은 SPARC: DISM (Dynamic Intimate Shared Memory) 대형 페이지 지원를 참조하십시오.


반응형
Posted by [PineTree]
ORACLE/Backup & Recovery2012. 8. 8. 11:10
반응형

● clone DB를 이용한 incomplete recovery 실습1

  ◎ User Managed

실습 순서

1. 실습을 위한 환경 설정
   ① whole backup
   ② 테이블 생성 -> 데이터 입력 -> 테이블 삭제 (recovery 확인용)

2. clone DB를 이용한 복구
   ① control file 및 parameter file 준비
   ② datafile backup, online redo log file, archive log file 복사
   ③ startup nomount -> control file 생성 -> 불완전 복구
   ④ clone DB에서 export -> devdb로 import
   ⑤ clone database 종료 및 삭제



    1. 실습을 위한 환경 설정 : ① whole backup       


OS] export ORACLE_SID=devdb
OS] sqlplus / as sysdba
-- 기존의 backup 및 archived log file 삭제
SQL> !rm -rf $ORACLE_BASE/oradata/devdb_backup
SQL> !rm -rf $ORACLE_BASE/oradata/devdb_arch
-- archive log file 위치를 다시 설정
SQL> !mkdir $ORACLE_BASE/oradata/devdb_arch
SQL> alter system set log_archive_dest_1 = 'location=$ORACLE_BASE/oradata/devdb_arch/';
SQL> alter system switch logfile;
SQL> !ls $ORACLE_BASE/oradata/devdb_arch
  1_2_706222899.dbf
-- 정상종료 및 whole backup
SQL> shutdown immediate
SQL> !mkdir $ORACLE_BASE/oradata/devdb_backup
SQL> !cp $ORACLE_BASE/oradata/devdb/* $ORACLE_BASE/oradata/devdb_backup
SQL> startup
SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
devdb 



    1. 실습을 위한 환경 설정 : ② 테이블 생성 -> 데이터 입력 -> 테이블 삭제 (recovery 확인용)


  SQL> drop table phil.t1 purge;
drop table phil.t1 purge
                *
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> create table phil.t1 (no number);
SQL> insert into phil.t1 values (1000);
SQL> insert into phil.t1 values (2000);
SQL> commit;
SQL> select * from phil.t1;
        NO
----------
      1000
      2000
SQL> alter system switch logfile;
SQL> alter system switch logfile;
SQL> alter system switch logfile;
SQL> alter system switch logfile;
SQL> alter system switch logfile;
SQL> !date                         
  2009. 12. 21. (월) 22:56:38 KST            -- 반드시 확인할 것.

SQL> alter system switch logfile;
SQL> drop table phil.t1 purge;
SQL> select * from phil.t1;
select * from phil.t1
                   *
ERROR at line 1:
ORA-00942: table or view does not exist



    2. clone DB를 이용한 복구 : ① control file 및 parameter file 준비


   SQL> !mkdir $ORACLE_BASE/oradata/devdb_clone

  SQL> alter database backup controlfile to trace;                 -- control file을 재생성할 수 있는 스크립트를 생성.
SQL> select d.value||'/'||p.value||'_ora_'||s.spid||'.trc' as trace_file_name
     from (select value from v$parameter where name = 'instance_name') p,
          (select value from v$parameter where name = 'user_dump_dest') d,
          (select spid  from v$process   where addr = (select paddr from v$session
                                                       where sid = (select sid from v$mystat
                                                                    where rownum = 1))) s;
     TRACE_FILE_NAME
     --------------------------------------------------------------------
     /u01/app/oracle/product/10.2.0/db_1/rdbms/log/devdb_ora_24567.trc
-- 컨트롤 파일 생성을 위한 준비
SQL> !cp /u01/app/oracle/product/10.2.0/db_1/rdbms/log/devdb_ora_24567.trc $ORACLE_BASE/oradata/devdb_clone/control_file_create.sql
-- 파라미터 파일을 위한 준비
SQL> create pfile='$ORACLE_HOME/dbs/initC1.ora' from spfile;
SQL> !ls $ORACLE_BASE/oradata/devdb_clone
  control_file_create.sql 
-- 다음처럼 control file 생성을 위한 명령을 편집한다.
SQL> !vi $ORACLE_BASE/oradata/devdb_clone/control_file_create.sql
CREATE CONTROLFILE set DATABASE "C1" RESETLOGS  ARCHIVELOG    -- set 부분, DB 이름 부분
    MAXLOGFILES 16
    MAXLOGMEMBERS 2
    MAXDATAFILES 30
    MAXINSTANCES 1
    MAXLOGHISTORY 292
LOGFILE
  GROUP 1 (
    '/u01/app/oracle/oradata/devdb_clone/redo01_a.log',       -- devdb_clone 경로
    '/u01/app/oracle/oradata/devdb_clone/redo01_b.log'
  ) SIZE 20M,
  GROUP 2 (
    '/u01/app/oracle/oradata/devdb_clone/redo02_a.log',
    '/u01/app/oracle/oradata/devdb_clone/redo02_b.log'
  ) SIZE 20M
-- STANDBY LOGFILE
DATAFILE
  '/u01/app/oracle/oradata/devdb_clone/system01.dbf',
  '/u01/app/oracle/oradata/devdb_clone/undotbs01.dbf',
  '/u01/app/oracle/oradata/devdb_clone/sysaux01.dbf',
  '/u01/app/oracle/oradata/devdb_clone/undo01.dbf',
  '/u01/app/oracle/oradata/devdb_clone/user_tab_ts.dbf',
  '/u01/app/oracle/oradata/devdb_clone/user_ind_ts.dbf'
CHARACTER SET US7ASCII
;
위의 내용만 두고 아래쪽은 모두 삭제한다.
SQL> -- 다음처럼 pfile을 편집한다.
SQL> !vi $ORACLE_HOME/dbs/initC1.ora
*.compatible='10.2.0'
*.control_files='/u01/app/oracle/oradata/devdb_clone/control01.ctl'
*.db_block_size=4096
*.db_name='C1'
*.log_archive_dest_1='location=$ORACLE_BASE/oradata/devdb_clone/'
*.pga_aggregate_target=60M
*.sga_target=200M
*.undo_management='auto'
*.undo_tablespace='undotbs01'



    2. clone DB를 이용한 복구 : ② datafile backup, online redo log file, archive log file 복사


  -- 백업해둔 데이터 파일 복사
  SQL> !ls $ORACLE_BASE/oradata/devdb_clone
control_file_create.sql
SQL> !cp $ORACLE_BASE/oradata/devdb_backup/*.dbf $ORACLE_BASE/oradata/devdb_clone
SQL> !ls $ORACLE_BASE/oradata/devdb_clone
control_file_create.sql  sysaux01.dbf  system01.dbf  temp01.dbf  undo01.dbf  undotbs01.dbf  user_ind_ts.dbf  user_tab_ts.dbf
-- 사용중인 online redo log 파일 복사
SQL> !cp $ORACLE_BASE/oradata/devdb/*.log $ORACLE_BASE/oradata/devdb_clone
SQL> !ls $ORACLE_BASE/oradata/devdb_clone
control_file_create.sql  redo01_b.log  redo02_b.log  system01.dbf  undo01.dbf     user_ind_ts.dbf
redo01_a.log             redo02_a.log  sysaux01.dbf  temp01.dbf    undotbs01.dbf  user_tab_ts.dbf
-- archived redo log 파일 복사
SQL> !cp $ORACLE_BASE/oradata/devdb_arch/* $ORACLE_BASE/oradata/devdb_clone
SQL> !ls $ORACLE_BASE/oradata/devdb_clone
1_19_706222899.dbf  1_22_706222899.dbf  control_file_create.sql  redo02_a.log  system01.dbf  undotbs01.dbf
1_20_706222899.dbf  1_23_706222899.dbf  redo01_a.log             redo02_b.log  temp01.dbf    user_ind_ts.dbf
1_21_706222899.dbf  1_24_706222899.dbf  redo01_b.log             sysaux01.dbf  undo01.dbf    user_tab_ts.dbf
SQL> exit



    2. clone DB를 이용한 복구 : ③ startup nomount -> control file 생성 -> 불완전 복구


[oracle@ora10gr2 oradata]$ export ORACLE_SID=C1
[oracle@ora10gr2 oradata]$ sqlplus / as sysdba
SQL> startup nomount
SQL> select instance_name, status from v$instance;
INSTANCE_NAME    STATUS
---------------- ------------
C1               STARTED
SQL> @ $ORACLE_BASE/oradata/devdb_clone/control_file_create.sql
SQL> select instance_name, status from v$instance;
INSTANCE_NAME    STATUS
---------------- ------------
C1               MOUNTED

SQL> -- 위에서 확인했던 날짜와 시간을 잘 확인해서 아래 명령을 완성한다.
SQL> recover database until time '2009-12-21 22:56:38' using backup controlfile;
ORA-00279: change 273942 generated at 12/21/2009 21:22:11 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/oradata/devdb_clone/1_14_706222899.dbf
ORA-00280: change 273942 for thread 1 is in sequence #14
Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
--> auto 입력
... 생략 ...
ORA-00308: cannot open archived log
'/u01/app/oracle/oradata/devdb_clone/1_19_706222899.dbf'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3
SQL> -- online redo log 파일을 계속 적용해야 하므로 파일 이름을 확인해서 사용한다.
SQL> select member from v$logfile;
MEMBER
--------------------------------------------------------------------------------
/u01/app/oracle/oradata/devdb_clone/redo01_a.log
/u01/app/oracle/oradata/devdb_clone/redo01_b.log
/u01/app/oracle/oradata/devdb_clone/redo02_a.log
/u01/app/oracle/oradata/devdb_clone/redo02_b.log
SQL> recover database until time '2009-12-21 22:56:38' using backup controlfile;
ORA-00279: change 274060 generated at 12/21/2009 21:34:32 needed for thread 1
ORA-00289: suggestion : /u01/app/oracle/oradata/devdb_clone/1_19_706222899.dbf
ORA-00280: change 274060 for thread 1 is in sequence #19
Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
--> /u01/app/oracle/oradata/devdb_clone/redo01_a.log 입력
SQL> select instance_name, status from v$instance;
INSTANCE_NAME    STATUS
---------------- ------------
C1               MOUNTED
SQL> alter database open resetlogs;
SQL> select * from phil.t1;
        NO
----------
      1000
      2000
SQL> exit



    2. clone DB를 이용한 복구 : ④ clone DB에서 export -> devdb로 import


 
[oracle@ora10gr2 devdb_clone]$ exp phil/phil file=t1.dmp tables=t1
About to export specified tables via Conventional Path ...
. . exporting table                             T1          2 rows exported
Export terminated successfully without warnings.
[oracle@ora10gr2 devdb_clone]$ export ORACLE_SID=devdb
[oracle@ora10gr2 devdb_clone]$ sqlplus phil/phil
SQL> select * from phil.t1;
select * from phil.t1
                   *
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> ! imp phil/phil file=t1.dmp tables=t1;
SQL> select * from phil.t1;
        NO
----------
      1000
      2000
SQL> exit



    2. clone DB를 이용한 복구 : ⑤ clone database 종료 및 삭제


[oracle@ora10gr2 devdb_clone]$ cd
[oracle@ora10gr2 ~]$ export ORACLE_SID=C1
[oracle@ora10gr2 ~]$ sqlplus / as sysdba
SQL> shutdown abort
SQL> exit
[oracle@ora10gr2 ~]$ ls /u01/app/oracle/oradata
[oracle@ora10gr2 ~]$ rm -rf /u01/app/oracle/oradata/devdb_clone
반응형
Posted by [PineTree]