Database/Oracle2012. 3. 11. 14:33

XMLAGG

문법

 

XMLAgg::=
Description of XMLAgg.gif follows

그림 설명

목적

 

XMLAgg함수는 집계 함수이다. XML fragment(조각)의 집합체를 취해서, 집계된 XML 문서를 반환한다. NULL을 반환하는 인수는 결과로부터 제거된다.

XMLAgg는 XMLAgg가 Node의 집합체를 반환하는 점을 제외하고는 SYS_XMLAgg와 유사하다. XMLFormat Object를 이용한 포맷을 받아들이지 않는다. 또한, XMLAgg는 SYS_XMLAgg처럼 요소 태그를 출력에서 둘러싸지 않는다.

Order_by_clause구문에서, 오라클 데이터 베이스는 열의 위치처럼 수치 문자를 설명하지 않고, 단지 수치 문자로 설명한다.


참 조 :

XMLELEMENT and SYS_XMLAGG

예제

 

다음 예제는 요소의 항목으로써 종업원 작업 ID와 이름과 함께 종업원 요소를 포함한 부서 요소를 산출한다.

SELECT XMLELEMENT("Department",
                  XMLAGG(XMLELEMENT("Employee", 
                         e.job_id||' '||e.last_name)
                         ORDER BY last_name))
   as "Dept_list"     
FROM employees e
WHERE e.department_id = 30;

Dept_list
-------------------------------------------------------------
<Department>
  <Employee>PU_CLERK Baida</Employee>
  <Employee>PU_CLERK Colmenares</Employee>
  <Employee>PU_CLERK Himuro</Employee>
  <Employee>PU_CLERK Khoo</Employee>
  <Employee>PU_MAN Raphaely</Employee>
  <Employee>PU_CLERK Tobias</Employee>
</Department>

아래 결과는 단일행이다. XMLAgg는 행을 집계하기 때문이다. 다중 그룹에서 반환되는 행을 그룹화 하기 위하여 GROUP BY를 이용할수 있다.

SELECT XMLELEMENT("Department",
      XMLAGG(XMLELEMENT("Employee", e.job_id||' '||e.last_name)))
   AS "Dept_list"
   FROM employees e
   GROUP BY e.department_id;

Dept_list
---------------------------------------------------------
<Department>
  <Employee>AD_ASST Whalen</Employee>
</Department>

<Department>
  <Employee>MK_MAN Hartstein</Employee>
  <Employee>MK_REP Fay</Employee>
</Department>

<Department>
  <Employee>PU_MAN Raphaely</Employee>
  <Employee>PU_CLERK Khoo</Employee>
  <Employee>PU_CLERK Tobias</Employee>
  <Employee>PU_CLERK Baida</Employee>
  <Employee>PU_CLERK Colmenares</Employee>
  <Employee>PU_CLERK Himuro</Employee>
</Department>
. . .
출처 : http://www.statwith.pe.kr/ORACLE/functions200.htm
Posted by 아로나
Database/Oracle2012. 2. 3. 11:09


1. RANK()함수는 말 그대로 랭킹, 즉 순위를 반환하는 함수이다.

SELECT EMPLOYEE_ID, SALARY,
 RANK() OVER (ORDER BY SALARY DESC) SALARY_RANKING
FROM EMPLOYEES;

2. DENSE_RANK()함수 역시 순위를 반환하지만 사원 급여가 같아 공돈 2위가 2명일 경우 3위는 사라지고 그 다음 4위가 반환되는데 2위 다음 3위가로 바로 나오게 할 경우 사용하는 함수이다.

SELECT EMPLOYEE_ID, SALARY,
 RANK() OVER (ORDER BY SALARY DESC) RANKING1,
 DENSE_RANK() OVER (ORDER BY SALARY DESC) RANKING2
FROM EMPLOYEES;


3. ROW_NUMBER함수는 1부터 시작해서 각 로우별로 순차적으로 값을 반환하다. 중복없음.

SELECT EMPLOYEE_ID, SALARY,
 RANK() OVER (ORDER BY SALARY DESC) RANKING1,
 DENSE_RANK() OVER (ORDER BY SALARY DESC) RANKING2,
 ROW_NUMBER() OVER (ORDER BY SALARY DESC) RANKING3
FROM EMPLOYEES;


--조회 결과(오라클 기본계정인 HR로 테스트를 해보았다.)

=> RANKING 1, 2, 3 이 서로 다른 결과를 나타내는 것을 알 수 있다.


4. 응용편 : ROW_NUMBER()함수를 이용하여 상위 N명의 명단을 추출해보자. 물론 이 경우 인라인뷰를 사용한다.

SELECT T.*
 FROM ( SELECT DEPARTMENT_ID, LAST_NAME, SALARY ,
                ROW_NUMBER() OVER(PARTITION BY DEPARTMENT_ID
         ORDER BY SALARY DESC) SAL
              FROM EMPLOYEES) T
WHERE T.SAL <= 3;

=> partion by 를 이용함으로서 부서별로 상위 3명을 추출하는 쿼리.

--조회결과(이 역시도 오라클 기본계정인 HR로 테스트)

==> 부서별로 상위 3명까지 나타내는 것을 알 수 있다.

출처 : 극히일부분 자작 + http://bench87.tistory.com/182

Posted by 아로나
Database/Oracle2012. 2. 3. 10:47


기본적으로는 다음과 같다.

LEAD() - 다음값
LAG() - 이전값

* 사용법
- LAG(), LEAD() 함수 사용시 필수 입력사항 : OVER(ORDER BY )
- LAG(A, B, C) A:대상로우, B:가져와서 뿌져줄 시작로우(대상로우 이전값 출력됨, default:1), C:대상로우 이전값이 없는 경우 채울 값(default:Null)
- LEAD(A, B, C) A:대상로우, B:가져와서 뿌져줄 시작로우(대상로우 다음값 출력됨, default:1), C:대상로우 다음값이 없는 경우 채울 값(default:Null)


* 테스트를 해보자

with TestTable as
(
select 0 Cat from dual union all
select 1 Cat from dual union all
select 3 Cat from dual union all
select 6 Cat from dual union all
select 10 Cat from dual union all
)
select Cat
LAG(Cat, 1) over (order by cat) prev_value,
LEAD(Cat, 1) over (order by cat) next_value,
Cat - LAG(Cat, 1) over (order by cat) Gap_By_Prev_Value,
Cat - LEAD(Cat, 1) over (order by cat)  Gap_By_Next_value
from TestTable;

-- result

  

  CAT PREV_VALUE NEXT_VALUE GAP_BY_PREV_VALUE GAP_BY_NEXT_VALUE
1 0       1      -1
2 1    0     3    1    -2
3 3    1     6    2    -3
4 6    3    10    3    -4
5 10    6      4  

=> Prev_value 와 Next_value 에서 Null값(빈칸)으로 표시된 부분들은 대상로우의 이전값 혹은 다음값이 없는 경우에 해당한다.

출처 : 극히일부자작 + http://www.jjimkorea.pe.kr/213 + http://blog.naver.com/with0utme?Redirect=Log&logNo=60151872512

  
Posted by 아로나
Database/Oracle2011. 12. 26. 17:13
여러방법이 있겠지만 현재 내가 쓴것.


 query란 변수에 데이터를 가져오는 sql문이 들어가 있을 경우.
(java파일에서 작성한다고 가정할때)

ex>
query = "select * from test";


SELECT * FROM
(
    SELECT ROWNUM AS RNUM, GET.* FROM 
    (             
+ query + (이곳에 데이터를 불러오는 쿼리문이 들어간다.)

    ) GET
   ORDER BY ROWNUM desc
)
WHERE RNUM BETWEEN 1 AND 10 ORDER BY RNUM ASC;


페이징 처리를 하기 위해선 전체 줄 수도 알아야 하기 때문에, 그를 알기위한 쿼리문


SELECT COUNT(*) CNT FROM ( + query + ) 


유의점. ROWNUM 사용시 alias를 필수로 지정해 주는게 좋다. ROWNUM그대로 쓰면 페이징 처리가 안되는 경우가 발생하기도 함. 

출처 : http://notpeelbean.tistory.com/36
Posted by 아로나
Database/Oracle2011. 11. 11. 11:10

# 클라이언트 다운받기
http://download.oracle.com/otn/nt/oracle10g/10201/10201_client_win32.zip 경로에서 해당 파일을 다운 받습니다. (여기에서 버전은 10.2.0.1.0 입니다.)

# 클라이언트 설치하기
1.  [setup.exe]를 클릭하고 시작 화면에서 [다음]을 클릭합니다.

* 처음 실행 시 CMD 창에서 oraparam.ini 파일 관련 에러가 발생하면 [Install] 폴더의 [oraparam.ini] 파일을 수정하면 됩니다.
------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [Certified Versions]
#You can customise error message shown for failure, provide value for CERTIFIED_VERSION_FAILURE_MESSAGE
#Windows=4.0,5.0,5.1,5.2
-> Windows=4.0,5.0,5.1,5.2 내용 앞의 # 표시를 삭제하고 저장한 후 다시 실행합니다.
------------------------------------------------------------------------------------------------------------------------------------------------------------------

2. [관리자]를 선택하고 [다음]을 클릭합니다.


3. 설치 경로를 지정하고 [다음]을 클릭합니다.


4. 필요 조건 검사를 하고 완료되면 [다음]을 클릭합니다.


5. 요약 사항을 확인하고 [설치]를 클릭합니다.


6. 설치가 진행됩니다.


7. 설치가 종료되면 [종료]를 클릭합니다.


# 클라이언트 설정하기
1. Net Manager 실행
[시작 - 프로그램 - Oracle - Oraclient10g_home1 - 구성 및 이전 툴 - Net Manager]를 실행합니다.


2. 리스너 추가하기
1) 리스너 탭에서 왼쪽 [+] 표시를 클릭하고 [확인]을 클릭합니다.


2) [주소 추가]를 클릭합니다.


3) 호스트는 자동으로 채워집니다. (현 사용자 pc의 호스트명에 맞게 채워짐)


3. 서비스 이름 지정하기
1) 서비스 이름 지정 탭에서 왼쪽의 [+] 버튼을 클릭합니다. 네트 서비스 이름은 임의로 입력해도 됩니다. (여기에선 [TEST]로 작성하고 [다음]을 클릭합니다.


2) 네트워크 프로토콜을 선택하고 [다음]을 클릭합니다.


3) 오라클이 설치되어있는 서버의 IP나 호스트 이름을 입력하고 [다음]을 클릭합니다.


4) 오라클 설치 서버의 [서비스 이름]을 입력하고 [다음]을 클릭합니다. (여기에선 orcl로 지정합니다.)


5) 접속이 잘 되는지 [테스트]를 클릭해 봅니다.


6) Scott/tiger 계정이 없으면 system/(설치 시 password)로 로그인 변경하여 테스트합니다.


7) 접속 테스트가 성공되면 [닫기]를 클릭합니다.


8) [완료]를 클릭합니다.


9) 완료된 화면입니다.

* 파일탭을 눌러서 네트워크구성 저장을 클릭합니다. (필히 저장을 해줘야 동작합니다.)



# SQLPLUS 실행하기
1. 아래 경로에서 SQLPLUS를 실행합니다.


2. SQLPLUS 로그온 화면이 나타납니다.

- 사용자 이름 : 사용자 계정의 이름을 입력  ex)sys, system 등
- 암호 : 각 계정의 암호를 입력
- 호스트 문자열 : 네트 서비스 이름을 입력 (여기에선 TEST로 진행하였습니다.)

3. SQLPLUS 실행 화면이 나타납니다.


출처 : http://www.cyworld.com/gil098/7470632

Posted by 아로나
Database/Oracle2011. 11. 2. 00:04


First of all, make sure the database is started. If it is not, you'll get this message (In 10g release 2).

C:>sc query OracleServiceXE

SERVICE_NAME: OracleServiceXE
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
                                (NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 1077       (0x435)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

C:>sqlplus myuser@xe

SQL*Plus: Release 10.2.0.1.0

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Enter password:
ERROR:
ORA-12514: TNS:listener does not currently know of service requested in connect
descriptor
If the database is running, probably the database hasn't registered yet with the listener.
This occurs when the database or listener just starts up.

Normally this problem should be solved by waiting a minute or so.

If you are using dynamic registration (using the local_listener database parameter), you can try to register the database service with the listener using the following command (from Oracle 9i onwards):
show parameter local listener
-- if the above is empty
alter system set local_listener='(address=(protocol=tcp)(host=localhost)(port=1521))';
alter system register;
If this does not work or you're using static registration, make sure the SERVICE_NAME entry used in the connection string (TNSNAMES.ORA, NAMES, OID, ...) matches a valid service know by the listener.
eg.
C:>tnsping ora920

TNS Ping Utility for 32-bit Windows: Version 9.2.0.7.0 - Production

Copyright (c) 1997 Oracle Corporation.  All rights reserved.

Used parameter files:
c:\oracle\ora920\network\admin\sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = DEV01)(PORT =
 2491))) (CONNECT_DATA = (SERVICE_NAME = UNKNOWN) (SERVER = DEDICATED)))
OK (20 msec)
As one can see, this is the connection information stored in a tnsnames.ora file:
ORA920.EU.DBMOTIVE.COM =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = DEV01)(PORT = 2491))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = UNKNOWN)
      (SERVER = DEDICATED)
    )
  )
However, the SERVICE_NAME UNKNOWN is not known by the listener at the database server side.
In order to test the known services by a listener, we can issue following command at the database server side:
C:>lsnrctl services

LSNRCTL for 32-bit Windows: Version 10.1.0.2.0 - Production

Copyright (c) 1991, 2004, Oracle.  All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=DEV01)(PORT=1521)))
Services Summary...
Service "ORA10G.eu.dbmotive.com" has 1 instance(s).
  Instance "ORA10G", status UNKNOWN, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:0 refused:0
         LOCAL SERVER
Service "ORA920.eu.dbmotive.com" has 2 instance(s).
  Instance "ORA920", status UNKNOWN, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:0 refused:0
         LOCAL SERVER
  Instance "ORA920", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:2 refused:0 state:ready
         LOCAL SERVER
The command completed successfully
Know services are ORA10G and ORA920.

Changing the SERVICE_NAME in our tnsnames.ora to a known service by the listener (ORA920.EU.DBMOTIVE.COM) solved the problem.

 

원본 :  http://www.dbmotive.com/ora-12514-tnslistener-does-not-currently-know-of-service-requested-in-connect-descriptor/
 

Posted by 아로나
Database/Oracle2011. 8. 21. 18:11

FUNCTION-BASED INDEX ( ORACLE 8I NEW FEATURE )
==============================================

Explanation
-----------

1. 개요

Function-based index는, 함수(function)이나 수식(expression)으로 계산
된 결과에 대해 인덱스를 생성하여 사용할 수 있는 기능을 제공한다.
질의 수행 시 해당 함수나 수식을 처리하여 결과를 가져 오는 것이 아니라,
인덱스 형태로 존재하는 미리 계산되어 있는 결과를 가지고 처리하므로
성능 향상을 기할 수 있다.

2. 제약사항

1) aggregate function 에 대한 function-based index 생성 불가.
(예 : sum(...) )

2) LOB, REF, nested table 컬럼에 대한 function-based index 생성 불가.

3. 주요 특징

1) cost-based optimizer에 의해 사용됨.
2) B*Tree / bitmap index로 생성 가능.
3) 산술식 (arithmetic expression), PLSQL function, SQL built-in
function 등에 적용 가능.

4) 함수나 수식으로 처리된 결과에 대한 range scan 가능
5) NLS SORT 지원
6) SELECT/DELETE를 할 때마다 함수나 수식의 결과를 계산하는 것이 아니라
INSERT/UPDATE 시 계산된 값을 인덱스에 저장.
7) 질의 속도 향상
8) object column이나 REF column에 대해서는 해당 object에 정의된
method에 대해 function-based index 생성 가능.

4. 생성 방법

CREATE [UNIQUE | BITMAP ] INDEX <index_name>
ON <tablename> (<index-expression-list>)

<index-expression-list> -> { <column_name> | <column_expression> }

예) CREATE INDEX EMP_NAME_INDEX ON EMP (UPPER(ENAME));
CREATE INDEX EMP_SAL_INDEX ON EMP( SAL + COMM, empno);

* Function-based index를 생성하기 위해서는 QUERY REWRITE 권한이
부여 되어 있어야만 한다.

예) GRANT QUERY REWRITE TO SCOTT;

5. Function-Based Index 사용을 위한 사전 작업

1) Function-based index는 cost based optimizer에서만 사용 가능하므로,
테이블에 대해 미리 analyze 해 주는 것이 바람직하다.
그리고 init 파일에서 OPTIMIZER_MODE 를 FIRST_ROWS 나 ALL_ROWS 등으
로 지정하거나 HINT 등을 사용하여 cost based optimizer가 사용되도록
한다.
2) init 파일에서 COMPATIBLE 파라미터 값을 8.1 이상으로 설정되어 있어야
한다.
( 예 : COMPATIBLE = 8.1.6 )
3) session/instance level 에서 QUERY_REWRITE_ENABLED 값이 TRUE 지정
되어 있어야 한다.
( 예 : ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; )

6. 예제

1) init 파라미터에서 다음과 같이 지정

compatible = 8.1.6 (반드시 8.1이상이어야 한다)
query_rewrite_enabled = true
query_rewrite_integrity = trusted

2) SCOTT 유저에서 function_based_index 생성

create index idx_emp_lower_ename
on emp
( lower(ename) ) ;

3) EMP table analyze

analyze table emp compute statistics ;

4) PLAN_TABLE 생성

@ ?/rdbms/admin/utlxplan.sql

5) Cost based optimizer 선택

alter session set optimizer_mode = FIRST_ROWS ;

6) Query 실행
explain plan set statement_id=''qry1'' FOR
select empno, ename
from emp
where lower(ename) = ''ford'' ;

7) PLAN 분석

SELECT LPAD('' '',2*level-2)||operation||'' ''||options||'' ''||object_name query_plan
FROM plan_table
WHERE statement_id=''qry1''
CONNECT BY prior id = parent_id
START WITH id = 0 order by id ;

-> 결과

QUERY_PLAN
------------------------------------------------
SELECT STATEMENT
TABLE ACCESS BY INDEX ROWID EMP
INDEX RANGE SCAN IDX_EMP_LOWER_ENAME

7. 결론

Function-based index는 적절하게 사용될 경우 성능상의 많은 이점을 가져
온다. Oracle8i Designing and Tuning for Performance에서도 가능한 한
Function-based index를 사용하는 것을 권장하고 있으며, LOWER(), UPPER()
등의 함수를 사용하여 불가피하게 FULL TABLE SCAN을 하는 경우에 대해서도
효과적으로 처리해 줄 수 있는 방안이라 할 수 있다.

출처 : 파란블로그 mystery님 블로그 http://blog.paran.com/testhan/228857

Posted by 아로나
Database/Oracle2011. 6. 25. 18:12

3.4 테스트를 통한 Undo Retention 및 Automatic Undo Retention 동작 방식 분석

Undo Retention 개요

언두 리텐션이란 지정된 수치(오라클 9i까지는 UNDO_RETENTION 파라미터의 설정 값) 동안은 트랜잭션이 종료된 후에라도,
트랜잭션과 관련되었던 언두 세그먼트를 재사용하지 못하도록 하는 기능이다.

하지만, 오라클 9i까지는 언두 테이블스페이스의 공간 부족 현상이 발생할 경우 지정된 수치에 도달하기 전에도 언두 세그먼트의
재사용이 가능하였다. 언두 리텐션 기능은 언두 세그먼트의 인그텐트 단위로 관리되며, 각 인스텐트 당 Commit Time 을 관리하여
언두 리텐션 기간을 계산하게 된다. 언두 리텐션과 관련된 내용은 언두 세그먼트 헤더 블록의 리텐션 테이블에서 관리된다.
커밋 전과 커밋 후의 리텐션 테이블의 변화 사항을 테스트를 통해 확인해보자.

Session_A>create table undo_layer_t2 ( c1 number ,c2 varchar2(10), c3 char(20)) ;
Table created.

Session_A>insert into undo_layer_t2 values ( 1, 'A','a');
1 row created.

Session_A>select sid from v$mystat where rownum = 1 ;

       SID
----------
       148

 

SYS_Session>select xidusn, xidslot, xidsqn
  2  from v$transaction
  3  where addr=(select taddr from v$session where sid = 148 ) ;

    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
         2         34        973

SYS_Session>alter system dump undo header '_SYSSMU2$';
System altered.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU2$' ;

 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2         25          8 EXPIRED
         1          2         33          8 EXPIRED
         2          2     204169       1024 ACTIVE

Session_A>commit ;
Commit complete.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU2$' ;

 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2         25          8 EXPIRED
         1          2         33          8 EXPIRED
         2          2     204169       1024 EXPIRED

SYS_Session>alter system dump undo header '_SYSSMU2$';
System altered.


-- Commit 전 
 Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1305867652
 Extent Number:1  Commit Time: 1305867652
 Extent Number:2  Commit Time: 1305867652

-- Commit 후
 Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1305867652
 Extent Number:1  Commit Time: 1305867652
 Extent Number:2  Commit Time: 1305867652

테스트 결과

( 결과 )

예상과 달리 DBA_UNDO_EXTNETS 뷰의 STATUS 칼럼 값은 EXPIRED 로 변경되고,
언두 리텐션 테이블의 Commit Time 수치에 아무런 변화가 없다.

( 예상 )

커밋 수행 후에는 언두 리텐션 테이블의 Commit Time 이 커밋 시점으로 변경되고, DBA_UNDO_EXTENTS 뷰의
STATUS 칼럼 값은 UNEXPIRED 로 변경될 것 이라고 예상
어떠한 트랜잭션을 수행해야만 UNEXPIRED 상태로 변경되는 것일까 ?

Undo Retention 동작방식 테스트

Case 1: 언두 세그먼트의 익스텐트를 1개 이상 사용하는 경우

Session_A>create table undo_layer_t3 ( c1 number,  c2 varchar2(10), c3 char(20)) ;
Table created.

Session_A>begin
  2  for i in 1 .. 10000 loop
  3  insert into undo_layer_t3 values (i, 'c2','c3');
  4  end loop ;
  5  commit ;
  6  end ;
  7  /
PL/SQL procedure successfully completed.

Session_A>delete from undo_layer_t3 where rownum <= 5000 ;
5000 rows deleted.

Session_A>select sid from v$mystat where rownum = 1 ; 

       SID
----------
       148

SYS_Session>select xidusn, xidslot, xidsqn
  2  from v$transaction
  3  where addr=(select taddr from v$session where sid = 148 ) ;

    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
         8          9        925

SYS_Session>alter system dump undo header '_SYSSMU8$';
System altered.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU8$';
 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2        121          8 ACTIVE
         1          2        385          8 ACTIVE
         2          2        393        128 ACTIVE

Session_A>commit ;
Commit complete.

 
SYS_Session>alter system dump undo header '_SYSSMU8$';
System altered.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU8$';

 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2        121          8 UNEXPIRED
         1          2        385          8 UNEXPIRED
         2          2        393        128 UNEXPIRED

 
-- 컷밋 전
Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1306119643
 Extent Number:1  Commit Time: 1305869453
 Extent Number:2  Commit Time: 1306119643

 
-- 컷밋 후
 Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1306123682
 Extent Number:1  Commit Time: 1306123682
 Extent Number:2  Commit Time: 1306123682

커밋 수행 후에는 언두 리텐션 테이블의 Commit Time 이 커밋 시점으로 변경되고,
DBA_UNDO_EXTENTS 뷰의 STATUS 칼럼 값은 UNEXPIRED 로 변경된 것을 확인 할 수 있다.

Case 2: 언두 세그먼트의 익스텐트 중에 UNEXPIRED 상태가 존재하는 경우

Session_A>delete from undo_layer_t3 where rownum = 1 ;
1 row deleted.

Session_A>select sid from v$mystat where rownum = 1 ; 

       SID
----------
       148

SYS_Session>select xidusn, xidslot, xidsqn
  2  from v$transaction
  3  where addr=(select taddr from v$session where sid = 148 ) ;

    XIDUSN    XIDSLOT     XIDSQN
---------- ---------- ----------
         4         27        944

SYS_Session>alter system dump undo header '_SYSSMU4$';
System altered.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU4$';

 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2         57          8 EXPIRED
         1          2         81          8 EXPIRED
         2          2       1929        128 ACTIVE
         3          2       2185        128 UNEXPIRED  ( 책내용 ) 

Session_A>commit ;
Commit complete.

SYS_Session>alter system dump undo header '_SYSSMU4$';
System altered.

SYS_Session>select extent_id, file_id, block_id, blocks, status 
  2  from dba_undo_extents
  3  where segment_name ='_SYSSMU4$';

 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS STATUS
---------- ---------- ---------- ---------- ---------------
         0          2         57          8 EXPIRED
         1          2         81          8 EXPIRED
         2          2       1929        128 UNEXPIRED
         3          2       2185        128 UNEXPIRED ( 책내용 ) 

  
-- 컷밋 전
Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1305880256
 Extent Number:1  Commit Time: 1305885617
 Extent Number:2  Commit Time: 1305885617
 Extent Number:3  Commit Time: 1305885617  ( 책내용 ) 
 
-- 컷밋 후
 Retention Table
  -----------------------------------------------------------
 Extent Number:0  Commit Time: 1305880256
 Extent Number:1  Commit Time: 1305885617
 Extent Number:2  Commit Time: 1305885617
 Extent Number:3  Commit Time: 1305885617  ( 책내용 )

커밋 수행 후에 DBA_UNDO_EXTENTS 뷰의 STATUS 칼럼 값은 UNEXPIRED 로 변경되었으나,
레텐션 테이블의 Commit Time 은 변경되지 않는다.

언두 세그먼트 익스텐트의 상태를 관리하는 원칙
● 일정 크기 이상의 언두 레코드를 발생시키는 트랜잭션의 경우에만
DBA_UNDO_EXTENTS 뷰의 STATUS 칼럼과 리텐션 테이블의 내용이 변경된다.
● 일정 크기 이하의 언두 레코드를 발생시키는 트랜잭션은
DBA_UNDO_EXTENTS 뷰의 STATUS 칼럼과 테이블의 내용을 변경시키지 않는다.
● 일정 크기 이하의 언두 레코드를 발생시키는 트랜잭션이 UNEXPIRED 상태의 익스텐트를
소유한 언두 세그먼트를 사용할 경우에는,
DBA_UNDO_EXTENTS 뷰의 STATUS 컬럼만 변경하고, 리텐션 테이블의 내용은 변경하지 않는다.

일정 크기 이하의 언두 레코드를 발생시키는 트랜잭션의 동작방식은 언두 세그먼트의 공간을 효율적으로 관리하고자
하는 목적에는 부합, 하지만, 커밋 수행 후에 언두 세그먼트의 인스텐트를 UNEXPIRED 로 변경하지 않고 EXPIRED로
변경함에 따라 ORA-0155의 발생가능성이 있는 것은 아닐까 ?
아마도, 오라클에서는 이러한 경우에도, 몇 가지 기법을 더 적용하여 효율적으로 ORA-1555의 발생을 최적화시킬 것으로
생각되지만, 테스트를 통해 이 부분을 파악하는 것은 무리이므로.. 여기까지만..

Automatic Undo Retention 개요

자동 언두 리텐션(automatic undo retention) 기능은 오라클 10g부터 제공하는 기능으로써,
다이나믹하게 언두 리텐션의 수치를 조절한다.

자동 언두 리텐션 기능을 제공함으로써 부적절하게 설정된 UNDO_RETENTION 파라미터로 인한 ORA-01555
발생을 최소화할 수 있다. 자동 언두 리텐션 기능의 동작 방식은 오라클 10gR1 과 오라클 10gR2간에도 차이가 나며,
undo guarantee 사용 여부와 언두 데이터 파일의 autoextend 사용 여부에 따라 다르게 동작한다.

언두 테이블스페이스를 undo guarantee 모드로 사용할 경우, 언두 리텐션을 보장한다.
즉, 언두 테이블스페이스의 공간 부족 현상이 발생할 경우에도, UNEXPIRED 된 언두 익스텐트를 재사용하는 것을
방지함으로써, 언두 리텐션을 보장하는 것이다.

오라클 9i까지는 언두 테이블스페이스가 부족한 경우, UNEXPIRED 된 언두 익스텐스를 재사용함에 따라 언두 리텐션을
보장하지 못하였다. 언두 테이블스페이스의 undo guarantee 사용 여부는 언두 테이블스페이스 생성 시점 또는 생성
후에 변경이 가능하다.

SYS_Session>select tablespace_name, retention
  2  from dba_tablespaces
  3  where tablespace_name ='UNDOTBS1'; 

TABLESPACE_NAME                RETENTION
------------------------------ ---------------------------------
UNDOTBS1                       NOGUARANTEE

SYS_Session>alter tablespace undotbs1 retention guarantee ;
Tablespace altered.

SYS_Session>select tablespace_name, retention
  2  from dba_tablespaces
  3  where tablespace_name ='UNDOTBS1'; 

TABLESPACE_NAME                RETENTION
------------------------------ ---------------------------------
UNDOTBS1                       GUARANTEE

SYS_Session>alter tablespace undotbs1 retention noguarantee ;
Tablespace altered.

SYS_Session>select tablespace_name, retention
  2  from dba_tablespaces
  3  where tablespace_name ='UNDOTBS1'; 
TABLESPACE_NAME                RETENTION
------------------------------ ---------------------------------
UNDOTBS1                       NOGUARANTEE

자동 언두 리텐션 기능으로 인해 재설정된 언두 리텐션 수치는 V$UNDOSTAT 뷰의 TUNED_UNDORETENTION 칼럼을 통해 확인할 수 있다.
V$UNDOSTAT 뷰는 오라클 9iR2부터 제공되며 언두 사용 통계정보를 10분 단위로 샘플링하며, 언두 사용에 대한 유용한 통계정보를 제공

Automatic Undo Retention 동작 방식 테스트

h3. 테스트를 위한 파라미터 기본 설정
- _UNDO_AUTOTUNE = TURE ( 기본설정 값 )
- UNDO_RETENTION = 0
h3. 테스트 초기화 
Session_A>create  table undo_layer_t4 as select * from dba_objects nologging ;
Table created.

테스트1 - Retention Guarantee = No Autoextend = No

Session_A>alter tablespace undotbs1 retention noguarantee ;
Tablespace altered.


Session_A>alter database datafile '/u01/app/oracle/db/TLO/undotbs01.dbf' autoextend off ;
Database altered.

 

SYS_Session>startup
ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size                  1223540 bytes
Variable Size             880805004 bytes
Database Buffers          188743680 bytes
Redo Buffers                2969600 bytes
Database mounted.
Database opened.
SYS_Session>@chk_undostat.sql

BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
14:27:34                 14:28:28                          0                                                600

SYS_Session>@chk_undostat.sql

BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
14:27:34                 14:28:49                          0                                             345600


SQL> !more t111.sql           
set linesize 140
col sql_text for a15

select count(*) from undo_layer_t444, undo_layer_t444, undo_layer_t444 ;

select to_char(a.begin_time,'HH24:MI:SS') begin,
       to_char(a.end_time,'HH24:MI:SS') end,
       a.maxquerylen max_q_len,
       a.maxqueryid max_q_id,
       a.tuned_undoretention tuned_ur,
       substr(b.sql_text,1,30) sql_text
from v$undostat a, v$sql b
where a.maxqueryid = b.sql_id(+)
and rownum <= 4
;
 

SQL> @t111.sql
  COUNT(*)
----------
1.5161E+10


BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ------------------------------
17:07:34                 17:15:55                        846 cw0wvgj78aq76                               345600    select count(*) from undo_laye
16:57:34                 17:07:34                        246 cw0wvgj78aq76                               345600    select count(*) from undo_laye
16:47:34                 16:57:34                       1327 cw0wvgj78aq76                               345600    select count(*) from undo_laye
16:37:34                 16:47:34                        727 cw0wvgj78aq76                               345600    select count(*) from undo_laye

테스트 1 - 결과 분석

오라클이 기동된 직후에 TUNED_UNDORETENTION 은 600초로 설정되며,
몇 분 후 345,600(96H) 초로 자동 설정된다. 345,600초(는 언두 테이블스페이스의 크기와 관련이 있는 것으로 보인다.
즉, 언두 테이블스페이스는 확장이 불가능하므로, 현재 크기에 해당되는 최대값으로 설정하는 것이며,
쿼리 수행 시에 MAXQUERYLEN, MAXQUERYID 컬럼에 값을 등록 한다.

테스트 2 - Retention Guarntee = No Autoextend = YES

SQL> alter tablespace undotbs1 retention noguarantee ;
Tablespace altered.

SQL> alter database datafile '/u01/app/oracle/db/TLO/undotbs01.dbf' autoextend on next 10m ;
Database altered.

SYS_Session>shutdown immediate ;
Database closed.
Database dismounted.
ORACLE instance shut down.
SYS_Session>startup
ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size                  1223540 bytes
Variable Size             880805004 bytes
Database Buffers          188743680 bytes
Redo Buffers                2969600 bytes
Database mounted.
Database opened.


SQL> @chk_undostat.sql

BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
17:42:21                 17:43:22                          0                                                600

....

SQL> @chk_undostat.sql

BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
17:42:21                 17:43:25                          0                                                600

SQL> @t111.sql

  COUNT(*)
----------
1.5161E+10


BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ------------------------------
17:52:21                 18:01:28                        948 0t9kys4buvt4y                                 1728 select ENQUEUE_ENABLED, DEQUEU
17:42:21                 17:52:21                        348 0t9kys4buvt4y                                 1188 select ENQUEUE_ENABLED, DEQUEU

테스트 2 - 결과 분석

오라클이 가동된 직후에 TUNED_UNDORETENTION 은 600초로 설정되며,
쿼리가 수행되지 않을 경우 TUNED_UNDORETNTION 은 600초로 유지한다.
장시간 쿼리가 수행될 경우에, MAXQUERYLEN 컬럼의 값은 300 초 단위로 갱신된다.
TUNED_UNDORETENTION 값은 장시간의 쿼리를 감지한 직후에는 대략 MAXQUERYLEN + UNDORETENTION + 60 초로 증가하며,
그 이후로는 매 60초 단위로 증가하게 된다.
즉, 언두 테이블스페이스가 확장 가능하므로, 쿼리의 수행시간에 근거하여 언두 리텐션을 튜닝한다.

테스트 3 - Retention Gurantee = YES Autoextentd = No

SQL> alter tablespace undotbs1 retention guarantee ;
Tablespace altered.
SQL> alter database datafile '/u01/app/oracle/db/TLO/undotbs01.dbf' autoextend off ;
Database altered.

SYS_Session>shutdown immediate ;
Database closed.
Database dismounted.
ORACLE instance shut down.
SYS_Session>startup
ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size                  1223540 bytes
Variable Size             880805004 bytes
Database Buffers          188743680 bytes
Redo Buffers                2969600 bytes
Database mounted.
Database opened.

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
18:25:06                 18:25:58                          0                                                600

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
18:25:06                 18:26:16                          0                                             345600

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
18:25:06                 18:25:58                          0                                                600

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
18:25:06                 18:26:16                          0                                             345600

테스트 결과3 의 내용은 테스트 1의 결과와 동일하다.

다만, undo guarantee 모드를 사용함에 따라, 언두 테이블스페이스의 공간 부족이 발생할 시점의 동작 방식이 차이가 있다.
undo guarantee 모드는 언두 리텐션을 보장하는 것에 우선순위가 있으므로, 언두 세그먼트를 확장하려고 시도하는
트랜잭션은 ORA-30036 이 발생한다.
undo gurantee 모드를 사용하지 않는다면, 이러한 경우, 다른 언두 세그먼트의 익스텐트를 스틸링(stealing)한다.

테스트 4 - Retention Gurantee = YES Autoextend = YES

SQL> alter tablespace undotbs1 retention guarantee ;
Tablespace altered.

SQL> alter database datafile '/u01/app/oracle/db/TLO/undotbs01.dbf' autoextend on next 10m ;
Database altered.

SQL> shutdown immediate ;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size                  1223540 bytes
Variable Size             880805004 bytes
Database Buffers          188743680 bytes
Redo Buffers                2969600 bytes
Database mounted.
Database opened.
SQL> 

 

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
08:40:40                 08:41:51                          0                                                600

SQL> @chk_undostat.sql
BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ---------------
08:40:40                 08:43:03                          0                                                600
 

SQL> @t111.sql

  COUNT(*)
----------
1.5161E+10

BEGIN                    END                       MAX_Q_LEN MAX_Q_ID                                  TUNED_UR SQL_TEXT
------------------------ ------------------------ ---------- --------------------------------------- ---------- ------------------------------
08:50:40                 08:59:36                        795 cw0wvgj78aq76                                 1518 select count(*) from undo_laye
08:40:40                 08:50:40                        195 cw0wvgj78aq76                                 1035 select count(*) from undo_laye

테스트 4 - 결과분석

테스트 결과의 내용은 테스트 2의 결과와 동일하다.
다만, undo guarantee 모드를 사용함에 따라, 언두 테이블스페이스의 공간 부족이 발생할 시점의
동작 방식이 차이가 있다는 것이다.

문서정보

Posted by 아로나
Database/Oracle2011. 6. 25. 17:52
Posted by 아로나
Database/Oracle2011. 6. 25. 17:33
안녕하세요...
rollback segment와 관련해서 질문이 한가지 있습니다.
현재 java source를 보면 대략 1000만건을 Select 하고서 조회한 데이타를 테이블에
insert를 합니다.
source를 잠시 보면

rs = stmt.executeQuery(" Select empno, ename, job from emp ");

pstmt = conn.prepareStatement(
                " Insert Into Temp (empno,  " +
                "                   ename,   " +
                "                   Job)   " +
                " Values (?,?,?)");

while(rs.next()) {
                pstmt.clearParameters();
                pstmt.setString(1, rs.getString("empno"));
                pstmt.setString(2, rs.getString("ename"));
                pstmt.setString(3, rs.getString("Job"));

                try {
                    pstmt.executeUpdate();
                } catch (SQLException se) {
                    System.out.println( "Message(execute) : " + se.getMessage());
                    System.out.println( "sql state(execute) : " + se.getSQLState());
                    System.out.println( "error code(execute) : " + se.getErrorCode());
                } catch (Exception e) {
                    System.out.println( "Insert Exception(execute) Error");
                }
            }

source는 대략 이러한 방식으로 되어있습니다.
그런데 이렇게 하다보니까 700만건도 못되어서 ORA-0155: snapshot too old" error가
발생하였습니다.

그래서 대량의 데이타를 처리할수 있는 rollback segment를 만들고 나서 다음과 같이
하였습니다.

위의 source에서 select를 하기 이전에 다음을 넣었습니다.

try {
                pstmt2 = conn.prepareStatement(
                    " set transaction use rollback segment TEMPRBS " );

                try {
                    pstmt2.executeUpdate();
                } catch (SQLException se) {
                    System.out.println( "Message(RBS) : " + se.getMessage());
                    System.out.println( "sql state(RBS) : " + se.getSQLState());
                    System.out.println( "error code(RBS) : " + se.getErrorCode());
                } catch (Exception e) {
                    System.out.println( "Insert Exception(RBS) Error");
                }
            } catch (SQLException se) {
                System.out.println( "Message(insert : RBS) : " + se.getMessage());
                System.out.println( "sql state(insert : RBS) : " + se.getSQLState());
                System.out.println( "error code(insert : RBS) : " + se.getErrorCode());
            } catch (Exception e) {
                System.out.println( "Insert Exception(RBS) Error");
            }

그런데 이렇게 하여도 ROLLBACK SEGMENT ERROR가 발생을 하는데 잘못된 부분이 어디 있는지
알고 싶습니다.

감사합니다...

제목 : Re: 2가지 방법...
글쓴이: 손님(guest) 2003/12/09 13:03:17 조회수:375 줄수:16  
이게 가능할지는 잘 모르겠네요...

일단 첫번째 방법으로 속도가 조금 떨어질 가능성은 있습니다만...
select를 할 경우에, order by를 사용하지 못할 특별한 이유가 없으면...
order by를 사용해 보는 게 좋을 듯하구요...
이걸로도 해결이 안되면...

두번째 방법은...
이건 오라클 9i일 경우(8i의 경우도 같은지 잘 모르겠네요...)에는...
UNDO_RETENTION을 조금 크게 잡아보심이...
쿼리가 실행되는 데 걸리는 시간 이상의 충분한 시간을 잡아보면 해결이 될지도...

뭐, 확실한 건 아닙니다만...
나쁘지 않다면 한번정도 테스트해 보심이 좋을 듯하네요...

그럼...

제목 : Re: rollback Segment 관리
글쓴이: 손님(claystudio) 2003/12/10 19:18:38 조회수:413 줄수:11  

insert 하다가 읽어 왔던 데이터가 바뀐것 같습니다.

"snapshot too old"오류를 자세히 찾아보시면 원인을 더 정확히 알 수 있을듯합니다...

ps. 데이터 양으로 봐서는 웹상에서 돌아가는 프로그램은 아니고 배치성 프로그램인듯 한데
    쿼리를 바꿔보심이...
    ==> Insert into Temp(empno, ename, job)
             Select empno, ename, job from emp;



제목 : Re: OTN에서 퍼왔습니다.
글쓴이: 손님(guest) 2003/12/12 15:43:22 조회수:905 줄수:147  
No. 20241

ORA-1555 (SNAPSHOT TOO OLD)의 일반적인 원인 및 조치사항
===========================================

PURPOSE
-------

ORA-1555 (snapshot too old)는 db 관리 업무에 익숙하지 않은 경우, rollback
관련된 오류 중 혼란을 일으키기 쉬운 오류이다.
이미 문서 <bulletin:11152>와 그외 자료가 이 오류를 설명하고 해결하기 위해
만들어져 있지만, ORA-1555 원인 파악을 위해 내용이 다소 길고 복잡하게
구성되어 있는 편이다.
여기에서는 발생 가능한 여러가지 원인 중 일반적인 원을을 위주로, 초보자도
쉽게 이해할 수 있도록 간단히 설명한다.


Explanation
-----------

일반적으로 ORA-1555에 혼란을 일으키는 원인은 한편으로는 오류 메시지 자체에
있다고 볼 수 있다.

ORA-1555: snapshot too old: rollback segment %s too small

이와 같은 오류에서 마치 ora-1555가 rollback segment에 write시 space가
부족해서 발생하는것으로 착각하는 사용자가 많다.

중요한 것은 ORA-1555는 rollback segment에 정보를 write시에 발생하는 것이
아니고 rollback segment로 부터 before image를 읽으려는 시점에서 발생한다는
것이다.

쉬운 예를 들어보자.

(1) 사원이 천명인 회사에서 select한 문장으로 그 전체 사원의 정보를 읽는데
    10분이 걸린다고 가정한다.
(2) 100번 사원 정보를 읽는데, 아직 읽지 않은 700번 사원에 대해 다른 session에서
    급여를 인상하는 update문장을 수행하고 commit을 한다.
    select문장은 lock을 걸지 않기 때문에 select도중 다른 update문장이
    수행되고 commit하는데 아무 문제가 없다.
(3) 1번에서 수행중인 select문장이 계속 진행되면서 700번 사원 정보를 읽으려고
    하면 이 정보가 수정되어 변경되었음을 알게 된다.
    그럼 select문장은 정보의 일관성을 위해 첫번째 사원을 읽기 시작한 시점의
    700번 사원에 대한 정보를 읽기 위해, 즉 before image를 읽기 위해
    rollback segment를 찾아간다.
(4) rollback segment내에 급여 인상 전 정보가 있으면 읽는다.
    단 이때,
    이 시스템에 트랜잭션이 매우 많아서 commit이 매우 많이 발생한 경우
    이미 2번에서 변경하고 commit한 정보는 다른 트랜잭션에서 overwrite했을
    수 있다.
    이런 경우 before image를 읽으러 간 select문장은 ora-1555를 만나게 되는
    것이다.
(5) 4번에서 ora-1555를 만난 경우 다시 동일한 select문장을 수행하면,
    이번에는 이미 급여가 인상된 후의 시점에서 시작하므로 700번 사원을
    읽는 경우에도 급여 인상전의 before image가 필요하지 않아 ora-1555는
    다시 발생하지 않을 수 있다.
    이러한 이유로 ora-1555는 발생했다 안했다 하는 식으로 일정하게 발생되지
    않고, 조치 방법이라는것도 100% 안전하기보다는 확률적으로 충분히 만나지
    않을 수 있는 환경을 만드는것이라고 볼 수 있다.

결국 ora-1555가 발생하는 것은 읽어야 하는 before image가 다른 트랜잭션에
의해 이미 overwrite되어 읽을 수 없는 경우 발생하므로, 발생하지 않게 하기
위해서는 데이타를 조회시 consistency를 유지해야 하는 시점동안 가능하면
오래 동안 rollback의 image가 유지되어야 하는것이다.

이렇게 이미 기록된 정보를 가능하면 오랜 기간동안 유지한다는 것은 새로운
트랜잭션의 기록을 위해 space를 확보해야 하는 작업과는 반대된다.
즉, ORA-1562와 같이 rollback segment를 write시에 space가 부족하여
space를 확보하기 위한 조치 방법과, 이 ORA-1555의 조치 방법을 서로 상충되어
trade-off가 있음을 주의해야 한다.

두 오류를 모두 피해가기 위해서는 일반적으로 매우 큰 rollback space가
도움이 된다.

ORA-1555의 일반적인 발생 경우 및 해결 방법을 정리한다.

(1) 트랜잭션에 비해 rollback segment 갯수가 적은 경우
    
    rollback segment하나에 동시에 기록 가능한 트랜잭션의 수는 rollback
    segment header내의 transaction table의 entry갯수로 제한되어 있다.
    이 수는 oracle version마다 다르지만 8i이상부터는 약 20개 정도이다.
    (transactions_per_rollback_segment의 지정과는 무관한다.)
    기본적으로 install시 생성되는 rollback segment는 4개인데, 이대로 놓고
    사용한다면, 결국 80 (20 * 4) 만큼의 commit이 발생하고 난 뒤에는
    다시 처음부터 transaction table의 entry 중 commit된 트랜잭션의
    정보를 가지는 entry의 정보를 overwrite하게 되는 것이다.

    해결 방법: rollback segment갯수를 증가시킨다.
               즉 새로운 rollback segment를 create시킨다.

    부작용: 제한된 rollback tablespace공간 내에서, 여러개의 rollback
            segment를 유지하는것은 하나의 rollback segment가 평균 가질 수
            있는 space가 그만큼 줄어드는 셈이다.
            이 부작용까지 줄이려면, rollback tablespace자체가 충분히
            커야 하고 space를 많이 요구하는 트랜잭션은 'set transaction
            use rollback segment' 문장을 이용하여 큰 rollback을 지정하여
            사용하도록 한다.

(2) rollback segment를 shrink하거나 optimal이 설정된 경우

    rollback segment를 shrink하거나 optimal을 지정하게 되면 이미 쓰여진
    rollback의 before image를 다른 트랜잭션이 overwrite도 하기 전에 미리
    지워 버리게 되는 셈이다.
    그러므로 이런 경우도 ora-1555의 원인이 된다.

    해결 방법: optimal을 너무 적게 지정하지 말고, shrink를 너무 자주
               하지 않는다. shrink를 수행 후 ora-1555가 발생하는 경우,
               단지 다시 조회하는것만으로 앞의 예제 (5)번에서 설명한
               이유로 인해, 해결되는 경우가 많다.

(3) proc와 같은 application에서 loop내의 fetch문장에서 자주 commit을
    하는 경우

    fetch문장은 loop를 도는 동안 일정하게 read consistency를 유지해야 한다.
    그리고 미리 cursor를 정의시에 데이타를 읽어두는것이 아니고, fetch시에
    loop를 돌면서 그때그때 데이타를 읽게 된다.
    그런데 loop내의 dml에 대해 너무 자주 commit을 하게 되면 그만큼
    여러개의 트랜잭션이 처리된 결과로 rollback segment의 transaction table이
    빨리 사용되고 overwrite되게 된다.

    해결 방법: loop내의 commit횟수를 줄인다. 예를 들어 loop를 돌때마다
               commit하게 하였다면 천번에 한번 혹은 만번 loop를 돈 후
               commit하는 식으로 늘려준다.

이 외에도 rollback tablespace자체의 space가 부족하여 transaction table의
entry들이 아직 overwrite되지도 않았는데, commit된 transaction이 사용한
rollback segment내의 space가 먼저 overwrite되는 경우도 있다.
그러나 일반적으로 rollback segment의 space를 너무 작게 유지하지는 않기
때문에 이렇게 space부족으로 ora-1555를 만나는 경우는 많지 않다.
이렇게 space가 절대적으로 부족한 경우는 rollback에 write하는 시점에서,
ora-1562가 먼저 발생하게 된다.

ora-1562에 대해서는 <bulletin:10823> "ORA-1562 분석 및 해결 방법
(ROLLBACK SEGMENT 크기 문제)"를 참조하고,
좀더 자세한 ora-1555의 개념에 대해서는 <bulletin:11152> "ORA-1555 원인
분석 및 조치 사항" 을 참조한다.

============================================================================

write할 rbs가 모자라서 그런 게 아니랍니다.
제 생각엔 루프안의 SQL에 대한 명시적인 트랜잭션 컨트롤 구문이 없는 것으로 보아
(commit or rollback) autocommit으로 그냥 사용중이신 것같은데요
autocommit을 꺼주시고 트랜잭션에 대한 매뉴얼한 컨트롤을 해주셔야할 듯합니다.
그냥... 명시적으로 commit과 rollback을 해주셔야할 듯하단 말입니다. ^^

직접적인 관련은 없는 듯하지만, rbs가 적다면 적절하게 늘려주시는 게 좋을 듯합니다.


- 출처 : http://www.ezslookingaround.com/blog/tech/?no=950 -
Posted by 아로나