4._동시성_구현_사례

조회 수 10563 추천 수 0 2013.09.05 09:42:10
dasini *.94.41.89

 

 

(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 ;

 ------------------------------------------------------

      . 동시성을 완벽하게 제어 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


시와처

2012.04.09 23:39:48
*.7.24.53

이력관리

  • 이력이란 : 시간의 흐름에 따라 정보가 변경된 내역
  • 이력의 종류
         - 점이력 : 발생시점만 관리하는 이력
            발생데이터 축적후 요약하여 보거나 단순 로그성 데이터로 이력을 관리하고자 하는 경우
         - 선분이력 : 해당 속성들이 일정 시점만의 정보가 아니라 일정 기간 동안 유효하다능 의미를 포함
           의미있는 정보의 시작일자와 종료일자를 관리하는 기법
          시계열 데이터를 다루는 경우 활용도가 높다.
이력.jpg


실습
1. 시점 이력 테이블 데이터 내역
select *  from tb_point_test;
NAME       START_TIME           ADDRESS
---------- -------------------- ----------------
성춘향     201001               송파
성춘향     201009               가산
성춘향     201106               사상
이몽룡     201001               제주
이몽룡     201106               독도
이몽룡     201201               해남
홍길동     200912               종로
홍길동     201006               서대문
홍길동     201012               종로
홍길동     201204               연희동

- 시점이력의 정보로 특정 년월(2011.10)의 거주 현황을 추출하고자 하는 경우
with vi_test
as   
(select a.name,a.start_time,a.address
       ,nvl(min(b.start_time),'999912') end_time
   from tb_point_test a
       ,tb_point_test b
  where a.name = b.name(+)
    and a.start_time < b.start_time(+)  
  group by a.name,a.start_time,a.address
)         
select *
  from vi_test
 where '201110' between start_time and end_time
;

NAME       START_TIME           ADDRESS        END_TIME
---------- -------------------- -------------- --------------------
이몽룡     201106               독도           201201
홍길동     201012               종로           201204
성춘향     201106               사상           999912


- 현재 시점의 정보 읽기
select *
  from tb_point_test
 where (name,start_time) in (select name,max(start_time) from tb_point_test group by name)
;

NAME       START_TIME           ADDRESS
---------- -------------------- ---------------
성춘향     201106               사상
이몽룡     201201               해남
홍길동     201204               연희동


2. 선분이력 테이블 
select *
  from tb_timeline_test
;
NAME       START_TIME           END_TIME             ADDRESS
---------- -------------------- -------------------- ------------------
성춘향     201009               201106               가산
홍길동     201006               201012               서대문
성춘향     201001               201009               송파
이몽룡     201001               201106               제주
이몽룡     201106               201201               독도
홍길동     200912               201006               종로
홍길동     201012               201204               종로
이몽룡     201201               999912               해남
성춘향     201106               999912               사상
홍길동     201204               999912               연희동
 

select *
  from tb_timeline_test
 where '201110' between start_time and end_time
NAME       START_TIME           END_TIME             ADDRESS
---------- -------------------- -------------------- -------------
이몽룡     201106               201201               독도
홍길동     201012               201204               종로
성춘향     201106               999912               사상


- 현재 시점의 상태 검색
select * from tb_timeline_test where end_time = '999912';
NAME       START_TIME           END_TIME             ADDRESS
---------- -------------------- -------------------- --------------
이몽룡     201201               999912               해남
성춘향     201106               999912               사상
홍길동     201204               999912               연희동
 




  • 이력 관리 종류
발생이력 (occurrence History)
변경이력 (Modification History)
진행이력 (Progress History)
  •  이력 관리 형태
시점이력 : new instance  가 생성되는 시점의 정보만을  보관
선분이력 : new instance  사 생성되는 시점에 직전 정보의 종료일자 변경
  • 이력관리 유형
인스턴스 레벨 이력관리
속성레벨 이력관리

첨부