메뉴 건너뛰기

bysql.net

3. 비관적 vs. 낙관적 동시성 제어

2010.06.07 02:26

휘휘 조회 수:8210


  • 비관적 동시성 제어 (Pessimistic Concurrency Control)
    • 사용자들이 같은 데이터를 동시에 수정할것이라고 가정
    • 사용자가 데에터를 읽는 시점에 LOCK을 걸어 그 트랜젝션이 완료될때 까지 유지
  • 낙관적 동시성 제어 (Optimistic Concurrency Control)
    • 사용자들이 같은 데이터를 동시에 수정하지 않을 것이라고 가정
    • 데이터를 읽을때 Lock을 설정 하지 않음
    • 낙관적 동시성 제어를 사용하면 lock을 유지하는 시간이 매우 짧아져져 동시성이 높아짐


(1) 비관적 동시성 제어

SQL> create table cuspoint as select '5' as no,'1000' as point from dual;

tx1

tx2
 SQL> select point from cuspoint where no=5 for update;

POIN
----
1000
t1


t2
SQL> select * from cuspoint where no='5';

N POIN
- ----
5 1000



t3
SQL> update cuspoint set point=point+1000 where no='5';


SQL>  update cuspoint set point=point+1000 where no='5';

1 row updated.
t4


SQL> commit;

Commit complete.


t5

1 row updated.



t6
SQL> SQL>  select * from cuspoint where no='5';

N POIN
- ----
5 3000




  • for update을 사용하여 해당 고객 레코드에 Lock 을 걸어둔후  tx1세션 종료후 tx2의 세션 수행



  • for update nowait --> 대기없이 Exception (Ora-00054) 를 던짐
  • for update wait 3 --> 3초 대기 후 Exception (Ora-30006)을 던짐


tx1

tx2
SQL>  select point from cuspoint where no=5
for update nowait;

POIN
----
2000


t1


t2

SQL>  select point from cuspoint where no=5
for update nowait;

 select point from cuspoint where no=5 for update nowait
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified


SQL>



SQL> commit;

Commit complete.


t3





(2) 낙관적 동시성 제어





select 적립포인트, 방문횟수, 최근방문잀, 구매실적 into :a,:b, :c,:d
from 고객
where 고객번호 =:cust_num;

계산

update 고객 set 적립포인트=:적립포인트
where 고객번호 =:cust_num
and 적립포인트 = :a
and 방문횟수 = :b
and 최근방문일시 = :c
and 구매실적 = :d;

if sql%rowcount = 0 then
    alert ('다른사용자에 의해 변경되었습니다.');
end if;


  • 컬럼이 많을 경우 별도의 수정일시 제어 컬럼을 뒤고 where 절에 사용하여 판단할수도 있음
  • 개발자가 애플리케이션 구현시 일일이 채크할수 있도록 변경해야함
  • 쿼리툴등을 통해 직업수행시 lost update등의 문제가 생길수 있음

  • 오라클 10g에서는 Pseudo 컬럼 ora_rowscn을 사용하여 관리 가능



ora_rowscn 

  • 오라클 default table 생성 / NoRowDependencies


tx1

tx2
SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796751 06-JUN-10 03.56.52.000000000 PM
      7499 ALLEN         2796751 06-JUN-10 03.56.52.000000000 PM
      7521 WARD          2796751 06-JUN-10 03.56.52.000000000 PM
      7566 JONES         2796751 06-JUN-10 03.56.52.000000000 PM
      7654 MARTIN        2796751 06-JUN-10 03.56.52.000000000 PM
      7698 BLAKE         2796751 06-JUN-10 03.56.52.000000000 PM
      7782 CLARK         2796751 06-JUN-10 03.56.52.000000000 PM
      7788 SCOTT         2796751 06-JUN-10 03.56.52.000000000 PM
      7839 Kinng         2796751 06-JUN-10 03.56.52.000000000 PM
      7844 TURNER        2796751 06-JUN-10 03.56.52.000000000 PM
      7876 ADAMS         2796751 06-JUN-10 03.56.52.000000000 PM
      7900 JAMES         2796751 06-JUN-10 03.56.52.000000000 PM
      7902 FORD          2796751 06-JUN-10 03.56.52.000000000 PM
      7934 MILLER        2796751 06-JUN-10 03.56.52.000000000 PM

14 rows selected.

SQL>


t1
SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
 from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796751 06-JUN-10 03.56.52.000000000 PM
      7499 ALLEN         2796751 06-JUN-10 03.56.52.000000000 PM
      7521 WARD          2796751 06-JUN-10 03.56.52.000000000 PM
      7566 JONES         2796751 06-JUN-10 03.56.52.000000000 PM
      7654 MARTIN        2796751 06-JUN-10 03.56.52.000000000 PM
      7698 BLAKE         2796751 06-JUN-10 03.56.52.000000000 PM
      7782 CLARK         2796751 06-JUN-10 03.56.52.000000000 PM
      7788 SCOTT         2796751 06-JUN-10 03.56.52.000000000 PM
      7839 Kinng         2796751 06-JUN-10 03.56.52.000000000 PM
      7844 TURNER        2796751 06-JUN-10 03.56.52.000000000 PM
      7876 ADAMS         2796751 06-JUN-10 03.56.52.000000000 PM
      7900 JAMES         2796751 06-JUN-10 03.56.52.000000000 PM
      7902 FORD          2796751 06-JUN-10 03.56.52.000000000 PM
      7934 MILLER        2796751 06-JUN-10 03.56.52.000000000 PM

14 rows selected.

SQL>



t2

SQL> update emp set ename='KING' where empno='7876';

1 row updated.


SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN)
from emp e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)

      7369 SMITH         2796831 06-JUN-10 04.00.40.000000000 PM
      7499 ALLEN         2796831 06-JUN-10 04.00.40.000000000 PM
      7521 WARD          2796831 06-JUN-10 04.00.40.000000000 PM
      7566 JONES         2796831 06-JUN-10 04.00.40.000000000 PM
      7654 MARTIN        2796831 06-JUN-10 04.00.40.000000000 PM
      7698 BLAKE         2796831 06-JUN-10 04.00.40.000000000 PM
      7782 CLARK         2796831 06-JUN-10 04.00.40.000000000 PM
      7788 SCOTT         2796831 06-JUN-10 04.00.40.000000000 PM
      7839 Kinng         2796831 06-JUN-10 04.00.40.000000000 PM
      7844 TURNER        2796831 06-JUN-10 04.00.40.000000000 PM
      7876 KING          2796831 06-JUN-10 04.00.40.000000000 PM
      7900 JAMES         2796831 06-JUN-10 04.00.40.000000000 PM
      7902 FORD          2796831 06-JUN-10 04.00.40.000000000 PM
      7934 MILLER        2796831 06-JUN-10 04.00.40.000000000 PM

14 rows selected.

SQL>


t3


  • tx1에서 scn 이 2796751이었어나 tx2에서 update 완료후 2796831
  • ora_rowscn 을 where 절에서 사용하여 낙관적 동시성 제어 수행 가능



  • rowdependences : 테이블 생성시 row단위로 scn 을 처리


SQL> create table t
rowdependences
nologging
as
select * from emp;


SQL> update t set ename='Kinng' where empno='7839';

SQL> commit;

Commit complete.

SQL> select e.empno,e.ename , ORA_ROWSCN,SCN_TO_TIMESTAMP(ORA_ROWSCN) from t e;

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)
---------- ---------- ---------- -------------------------------------
      7369 SMITH         2796616 06-JUN-10 03.50.47.000000000 PM
      7499 ALLEN         2796616 06-JUN-10 03.50.47.000000000 PM
      7521 WARD          2796616 06-JUN-10 03.50.47.000000000 PM
      7566 JONES         2796616 06-JUN-10 03.50.47.000000000 PM
      7654 MARTIN        2796616 06-JUN-10 03.50.47.000000000 PM
      7698 BLAKE         2796616 06-JUN-10 03.50.47.000000000 PM
      7782 CLARK         2796616 06-JUN-10 03.50.47.000000000 PM
      7788 SCOTT         2796616 06-JUN-10 03.50.47.000000000 PM
      7839 Kinng         2796737 06-JUN-10 03.56.13.000000000 PM
      7844 TURNER        2796616 06-JUN-10 03.50.47.000000000 PM
      7876 ADAMS         2796616 06-JUN-10 03.50.47.000000000 PM

     EMPNO ENAME      ORA_ROWSCN SCN_TO_TIMESTAMP(ORA_ROWSCN)
---------- ---------- ---------- ------------------------------------------
      7900 JAMES         2796616 06-JUN-10 03.50.47.000000000 PM
      7902 FORD          2796616 06-JUN-10 03.50.47.000000000 PM
      7934 MILLER        2796616 06-JUN-10 03.50.47.000000000 PM

14 rows selected.

SQL>



  • 참고) ora_rowscn  은 smon 프로세스가 관리하는 scn과 timestamp 매핑테이블에 영향을 받으며
    매핑테이블 갱신주기는 5일 (= scn으로 timestamp 를 확인할수 있는 시기는 5일)





참고 :


Thread: SELECT FOR UPDATE NOWAIT | WAIT 기능 소개
http://forums.oracle.com/forums/thread.jspa?threadID=471919&tstart=208



번호 제목 글쓴이 날짜 조회 수
27 9. ASH(Active Session History) 실천하자 2010.06.14 15606
26 8. Statspack / AWR balto 2010.06.13 12766
25 7. Response Time Analysis 방법론과 OWI file balto 2010.06.13 8062
24 5. 오라클 Lock file 휘휘 2010.06.07 26365
23 4. 동시성 구현 사례 토시리 2010.06.07 10932
» 3. 비관적 vs. 낙관적 동시성 제어 휘휘 2010.06.07 8210
21 2. 트랜잭션 수준 읽기 일관성 file 휘휘 2010.06.07 19567
20 4. DBMS_XPLAN 패키지 balto 2010.06.06 10461
19 3. SQL 트레이스 file balto 2010.06.06 21175
18 3장. 오라클 성능 관리 운영자 2010.06.06 6694
17 2. AutoTrace 실천하자 2010.06.06 8597
16 1. Explain Plan 실천하자 2010.06.06 14663
15 2장. 트랜잭션과 Lock 운영자 2010.06.01 6895
14 6. 문장수준 읽기 일관성 file 토시리 2010.06.01 10432
13 1. 트랜잭션 동시성 제어 실천하자 2010.05.31 8631
12 5. Undo file 토시리 2010.05.31 18650
11 11. Shared Pool file 실천하자 2010.05.31 18511
10 8. 블록 클린아웃 휘휘 2010.05.31 12282
9 7. Consistent vs. Current 모드 읽기 휘휘 2010.05.31 10537
8 10. 대기 이벤트 balto 2010.05.30 8010