메뉴 건너뛰기

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



번호 제목 글쓴이 날짜 조회 수
67 Front Page file 운영자 2010.05.17 154865
66 4. Prefetch file balto 2010.07.10 28434
65 5. 오라클 Lock file 휘휘 2010.06.07 26365
64 2. DB 버퍼 캐시 file 휘휘 2010.05.24 21916
63 3. SQL 트레이스 file balto 2010.06.06 21175
62 1. 기본 아키텍처 [1] file 휘휘 2010.05.23 19899
61 2. 트랜잭션 수준 읽기 일관성 file 휘휘 2010.06.07 19567
60 5. Undo file 토시리 2010.05.31 18650
59 11. Shared Pool file 실천하자 2010.05.31 18511
58 9. Static vs. Dynamic SQL [1] balto 2010.07.04 18343
57 4. Array Processing 활용 file 휘휘 2010.07.05 18238
56 1 장. 오라클 아키텍처 운영자 2010.05.20 17842
55 5. Fetch Call 최소화 file 휘휘 2010.07.05 16839
54 9. ASH(Active Session History) 실천하자 2010.06.14 15606
53 2. SQL 처리과정 file 휘휘 2010.06.28 15340
52 3. 버퍼 Lock [1] 휘휘 2010.05.24 15225
51 6. 바인드 변수의 부작용과 해법 file 실천하자 2010.06.28 14664
50 1. Explain Plan 실천하자 2010.06.06 14663
49 8. PL/SQL 함수 호출 부하 해소 방안 토시리 2010.07.11 14023
48 7. Result 캐시 휘휘 2010.07.19 12969