(1) 일련번호 채번 동시성 높이기
. Locking을 최소화 하면서 채번 테이블로부터 일련번호를 채번 하고자 할때 사용
. DBMS가 제공하는 Sequence 기능을 이용
but, 그럴수 없을때,
1. 데이터가 삽입되는 시점에 실시간으로 현재의 MAX값을 취해 1만큼 증가시킨 값을 이용
-> 두개의 트랜잭션이 동시에 같은 값을 읽었을 경우, insert 하려는 순간 PK 제약에 위배되므로 예외처리를 통해 동시성 제어
2. MAX 값을 관리하는 별도의 채번 테이블에 값을 가져오는 방식
-> 채번후 다음 처리로 진행하기 전에 채번 테이블 값을 1만큼 증가시키는 갱신을 수행해야 함
-------------------------------------------------------------------------------------------
--채번 테이블
create table seq_tab ( gubun varchar2(1), seq number, constraint pk_seq_tab primary key(gubun, seq) ) organization index;
--채번함수 정의create or replace function seq_nextval(l_gubun number) return number
as
/**pragma autonomous_transaction**/; l_new_seq seq_tab.seq%type; begin update seq_tab set seq = seq + 1 where gubun = l_gubun; select seq into l_new_seq from seq_tab where gubun = l_gubun; commit;-----------(A) return l_new_seq; end; /
--트랜잭션 예시
begin
update tab1
set col1 = :x
where col2 = :y ;
insert into tab2 -----------(B)
values (seq_nextval(123), :x, :y, :z);
loop
-- do anything ...
end loop;
commit;
exception
when others then
rollback;
end;
/ ------------------------------------------------------
but, (A) 라인에서 커밋을 한다면 어떤 이유에서 메인 트랜잭션이 (B) isert이후에 롤백될 경우
(A) 에서는 update가 이미 커밋된 상태가 되어 데이터 일관성이 깨짐
seq_nextval 함수에서 라인 14에서 커밋을 하지 않음
-> 메인 트랜잭션이 모두 종료될 때까지 채번 테이블이 Lock이 걸린 상태가 유지 되므로
동시 채번이 빈번히 발생하는 상황에서 심각한 성능 저하 초래
-> 오라클은 메인 트랜잭션에 영향을 주지 않고 서브 트랜잭션만 따로 커밋하는 기능 제공 (autonomous 트랜잭션)
seq_nextval 함수에서 /**pragma autonomous_transaction**/를 사용
Pragma Autonomous_Transaction
- 자율 트랜잭션
- 부모 트랜잭션의 승인/롤백 여부에 상관없이 자신의 작업을 승인하거나 롤백할 수 있다.
(2) 선분 이력 정합성 유지
. 선분이력을 추가하고 갱신할때 발생할수 있는 동시성 이슈
( 고객의 변경이력을 관리할 때 이력의 시작시점만을 관리하는 것을 '점이력' 모델이라고 하고,
시작시점과 종료시점을 함께 관리하는 것을 '선분이력' 모델이라고 한다.)

------------------------------------------------------
-- 기존 최종 선분이력을 끊고 새로운 이력 레코드를 추가하는 전형적인 처리 루틴
declare
cur_dt varchar2(14);
begin
select 고객ID
from 부가서비스이력
where 고객ID = 1
and 종료일시 = to_date('99991231235959', 'yyyymmddhh24miss')
for update nowait ;
select 고객ID
from 고객
where 고객ID = 1
for update nowait ;
cur_dt := to_char(sysdate, 'yyyymmddhh24miss') ; -- ①
update 부가서비스이력 -- ②
set 종료일시 = to_date(:cur_dt, 'yyyymmddhh24miss') - 1/24/60/60
where 고객ID = 1
and 부가서비스ID = 'A'
and 종료일시 = to_date('99991231235959', 'yyyymmddhh24miss') ;
insert into 부가서비스이력(고객ID, 부가서비스ID, 시작일시, 종료일시) -- ③
values (1, 'A', to_date(:cur_dt, 'yyyymmddhh24miss'),
to_date('99991231235959', 'yyyymmddhh24miss')) ;
commit; -- ④
end;
------------------------------------------------------
. 신규 등록시 -> update 문에서 실패, insert에서 1건
. 첫번째 트랜잭션이 1을 수행하고 2로 진입하기 직전에 두번째 트랜잭션이 동일이력에 대해
먼저 진행하면 선분 이력이 깨지게 됨
-> 직렬화 장치를 마련해야 함 -> 1번 문장이 수행되기 이전에 select for update 문을 이용해 해당 레코드에 Lock 설정
------------------------------------------------------
-- 부가 서비스 이력에 Lock을 걸어 동시성 관리
select 고객ID from 부가서비스이력
where 고객ID = 1
and 부가서비스 ID = 'A'
and 종료일시 = to_date('99999999999','yyyymmddhh24miss')
for update nowait ;
------------------------------------------------------
. 기존에 부가서비스 이력이 전혀 없든 고객일 경우 Lock이 걸리지 않음
--> 동시에 두개의 트랜잭션이 3번 insert에 진입가능 ---> 시작일시는 다르면서 종료일시가 같은 두개의 이력 레코드 생성
------------------------------------------------------
-- 고객 이력에 Lock을 걸음
select 고객ID from 고객
where 고객ID = 1
for update nowait ;
------------------------------------------------------
. 동시성을 완벽하게 제어
<p>이력관리</p><p></p><ul><li>이력이란 : 시간의 흐름에 따라 정보가 변경된 내역</li><li>이력의 종류</li></ul><div> - 점이력 : 발생시점만 관리하는 이력</div><div> 발생데이터 축적후 요약하여 보거나 단순 로그성 데이터로 이력을 관리하고자 하는 경우</div><div> - 선분이력 : 해당 속성들이 일정 시점만의 정보가 아니라 일정 기간 동안 유효하다능 의미를 포함</div><div> 의미있는 정보의 시작일자와 종료일자를 관리하는 기법</div><div> 시계열 데이터를 다루는 경우 활용도가 높다.</div><div><img src="files/attach/images/22119/841/023/c21d78365fca7105ee24a0691d9a164b.jpg" alt="이력.jpg" width="583" height="480" editor_component="image_link" /></div><div><br /></div><div><br /></div><div>실습</div><div><span style="font-family: monospace; ">1. 시점 이력 테이블 데이터 내역</span></div><div><div><span style="font-family: monospace; ">select * from tb_point_test;</span></div></div><div><div><span style="font-family: monospace; ">NAME START_TIME ADDRESS</span></div><div><span style="font-family: monospace; ">---------- -------------------- ----------------</span></div><div><span style="font-family: monospace; ">성춘향 201001 송파</span></div><div><span style="font-family: monospace; ">성춘향 201009 가산</span></div><div><span style="color: rgb(255, 0, 0); font-family: monospace; ">성춘향 201106 사상</span></div><div><span style="font-family: monospace; ">이몽룡 201001 제주</span></div><div><span style="color: rgb(255, 0, 0); font-family: monospace; ">이몽룡 201106 독도</span></div><div><span style="font-family: monospace; ">이몽룡 201201 해남</span></div><div><span style="font-family: monospace; ">홍길동 200912 종로</span></div><div><span style="font-family: monospace; ">홍길동 201006 서대문</span></div><div><span style="color: rgb(255, 0, 0); font-family: monospace; ">홍길동 201012 종로</span></div><div><span style="font-family: monospace; ">홍길동 201204 연희동</span></div></div><div><br /></div><div><span style="font-family: monospace; ">- 시점이력의 정보로 특정 년월(2011.10)의 거주 현황을 추출하고자 하는 경우</span></div><div><div><span style="font-family: monospace; ">with vi_test</span></div><div><span style="font-family: monospace; ">as </span></div><div><span style="font-family: monospace; ">(select a.name,a.start_time,a.address</span></div><div><span style="font-family: monospace; "> ,nvl(min(b.start_time),'999912') end_time</span></div><div><span style="font-family: monospace; "> from tb_point_test a</span></div><div><span style="font-family: monospace; "> ,tb_point_test b</span></div><div><span style="font-family: monospace; "> where a.name = b.name(+)</span></div><div><span style="font-family: monospace; "> and a.start_time < b.start_time(+) </span></div><div><span style="font-family: monospace; "> group by a.name,a.start_time,a.address</span></div><div><span style="font-family: monospace; ">) </span></div><div><span style="font-family: monospace; ">select *</span></div><div><span style="font-family: monospace; "> from vi_test</span></div><div><span style="font-family: monospace; "> where '201110' between start_time and end_time</span></div><div><span style="font-family: monospace; ">;</span></div></div><div><br /></div><div><div><div><span style="font-family: monospace; ">NAME START_TIME ADDRESS END_TIME</span></div><div><span style="font-family: monospace; ">---------- -------------------- -------------- --------------------</span></div><div><span style="font-family: monospace; ">이몽룡 201106 독도 201201</span></div><div><span style="font-family: monospace; ">홍길동 201012 종로 201204</span></div><div><span style="font-family: monospace; ">성춘향 201106 사상 999912</span></div></div></div><div><br /></div><div><br /></div><div><span style="font-family: monospace; ">- 현재 시점의 정보 읽기</span></div><div><div><span style="font-family: monospace; ">select *</span></div><div><span style="font-family: monospace; "> from tb_point_test</span></div><div><span style="font-family: monospace; "> where (name,start_time) in (select name,max(start_time) from tb_point_test group by name)</span></div></div><div><span style="font-family: monospace; ">;</span></div><div><br /></div><div><div><span style="font-family: monospace; ">NAME START_TIME ADDRESS</span></div><div><span style="font-family: monospace; ">---------- -------------------- ---------------</span></div><div><span style="font-family: monospace; ">성춘향 201106 사상</span></div><div><span style="font-family: monospace; ">이몽룡 201201 해남</span></div><div><span style="font-family: monospace; ">홍길동 201204 연희동</span></div></div><div><br /></div><div><br /></div><div>2. 선분이력 테이블 </div><div><div><span style="font-family: monospace; ">select *</span></div><div><span style="font-family: monospace; "> from tb_timeline_test</span></div><div><span style="font-family: monospace; ">;</span></div></div><div><div><span style="font-family: monospace; ">NAME START_TIME END_TIME ADDRESS</span></div><div><span style="font-family: monospace; ">---------- -------------------- -------------------- ------------------</span></div><div><span style="font-family: monospace; ">성춘향 201009 201106 가산</span></div><div><span style="font-family: monospace; ">홍길동 201006 201012 서대문</span></div><div><span style="font-family: monospace; ">성춘향 201001 201009 송파</span></div><div><span style="font-family: monospace; ">이몽룡 201001 201106 제주</span></div><div><span style="font-family: monospace; ">이몽룡 201106 201201 독도</span></div><div><span style="font-family: monospace; ">홍길동 200912 201006 종로</span></div><div><span style="font-family: monospace; ">홍길동 201012 201204 종로</span></div><div><span style="font-family: monospace; ">이몽룡 201201 999912 해남</span></div><div><span style="font-family: monospace; ">성춘향 201106 999912 사상</span></div><div><span style="font-family: monospace; ">홍길동 201204 999912 연희동</span></div><div><span style="font-family: monospace; "> </span></div></div><div><br /></div><div><div><span style="font-family: monospace; ">select *</span></div><div><span style="font-family: monospace; "> from tb_timeline_test</span></div><div><span style="font-family: monospace; "> where '201110' between start_time and end_time</span></div><div><span style="font-family: monospace; ">; </span></div></div><div><div><span style="font-family: monospace; ">NAME START_TIME END_TIME ADDRESS</span></div><div><span style="font-family: monospace; ">---------- -------------------- -------------------- -------------</span></div><div><span style="font-family: monospace; ">이몽룡 201106 201201 독도</span></div><div><span style="font-family: monospace; ">홍길동 201012 201204 종로</span></div><div><span style="font-family: monospace; ">성춘향 201106 999912 사상</span></div></div><div><br /></div><div><br /></div><div><span style="font-family: monospace; ">- 현재 시점의 상태 검색</span></div><div><span style="font-family: monospace; ">select * from tb_timeline_test where end_time = '999912';</span></div><div><div><span style="font-family: monospace; ">NAME START_TIME END_TIME ADDRESS</span></div><div><span style="font-family: monospace; ">---------- -------------------- -------------------- --------------</span></div><div><span style="font-family: monospace; ">이몽룡 201201 999912 해남</span></div><div><span style="font-family: monospace; ">성춘향 201106 999912 사상</span></div><div><span style="font-family: monospace; ">홍길동 201204 999912 연희동</span></div><div><span style="font-family: monospace; "> </span></div></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><ul><li>이력 관리 종류</li></ul></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div>발생이력 (occurrence History)</div></div><div><div>변경이력 (Modification History)</div></div><div><div>진행이력 (Progress History)</div></div></blockquote><div><ul><li> 이력 관리 형태</li></ul></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div>시점이력 : new instance 가 생성되는 시점의 정보만을 보관</div></div><div><div>선분이력 : new instance 사 생성되는 시점에 직전 정보의 종료일자 변경</div></div></blockquote><div><ul><li>이력관리 유형</li></ul></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div>인스턴스 레벨 이력관리</div></div><div>속성레벨 이력관리</div></blockquote><p></p>