지난 번에 Consistent 모드로 블록을 읽으면 읽기 일관성이 보장된다는 것을 알았다.


[Oracle] 오라클 다중 버전 읽기 일관성 모델 알아보기


이제 오라클에 존재하는 Consistent 모드 읽기와 Current 모드 읽기의 차이점에 대해 알아보도록 하자.



Consistent 모드 읽기

- 쿼리 실행 시간에 상관없이 항상 쿼리가 시작된 시점의 데이터를 가져옴

[ SQL Trace ]

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.41       1.15         66      28691       7235        7071

Fetch        0      0.00       0.00          0          0          0           0

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

total        2      0.41       1.16         66      28691       7235        7071


[ AutoTrace ]

Statistics

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

          0  recursive calls

       7235  db block gets

      28691  consistent gets

         66  physical reads

     663872  redo size

        935  bytes sent via SQL*Net to client

        979  bytes received via SQL*Net from client

          6  SQL*Net roundtrips to/from client

          1  sorts (memory)

          0  sorts (disk)

       7071  rows processed

   

① CR copy 생성 없이 Current 블록을 읽어도 집계에 포함

② SELECT 문에서 읽은 대부분의 블록

③ CR 블록을 생성하려고 읽어들인 Undo 세크먼트 블록도 집계에 포함


Current 모드 읽기

- 쿼리가 시작된 시점이 아닌 데이터를 찾아간 그 시점의 최종 값을 가져옴

[ SQL Trace ]

call     count       cpu    elapsed       disk      query    current        rows

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

Parse        1      0.00       0.00          0          0          0           0

Execute      1      0.41       1.15         66      28691       7235        7071

Fetch        0      0.00       0.00          0          0          0           0

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

total        2      0.41       1.16         66      28691       7235        7071


[ AutoTrace ]

Statistics

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

          0  recursive calls

       7235  db block gets

      28691  consistent gets

         66  physical reads

     663872  redo size

        935  bytes sent via SQL*Net to client

        979  bytes received via SQL*Net from client

          6  SQL*Net roundtrips to/from client

          1  sorts (memory)

          0  sorts (disk)

       7071  rows processed

   

① DML문 수행 시

② SELECT FOR UPDATE문 수행 시

③ disk sort가 필요할 정도의 대량 데이터를 정렬 시


음.. 뭔가 차이가 있다는 건 알겠는데 실제로 어떻게 적용되는건지 확 와닿지가 않..;;

예제를 통해 좀 더 생각해보자.


Consistent 모드로 갱신할 때 생기는 현상 


 TX1

 

 TX2

 UDPATE EMP SET SAL = SAL + 100

  WHERE EMPNO = 7788;

t1

 

 

t2

 UDPATE EMP SET SAL = SAL + 200

  WHERE EMPNO = 7788;

 COMMIT; 

t3

 

 

t4

 COMMIT; 

① TX2는 TX1에 걸린 Lock 대기 (Row Lock)

② t2 시점에 SAL은 1000이었므로 TX1이 commit된 후 1,000을 가지고 UDPATE (Read Committed라고 가정)

③ 최종값은 1200이 되고 TX1의 처리 결과는 사라짐, Lost Update 발생


Current 모드로 갱신할 때 생기는 현상 


 TX1

 

 TX2

 UDPATE EMP SET SAL = 2000

  WHERE EMPNO = 7788

    AND SAL = 1000;

t1

 

 

t2

 UDPATE EMP SET SAL = 3000

  WHERE EMPNO = 7788

    AND SAL = 2000;

 COMMIT; 

t3

 

 

t4

 COMMIT; 

① TX2는 TX1에 걸린 Lock 대기 (Row Lock)

② SAL 값이 2,000으로 UPDATE 된 것을 확인 후 UPDATE 수행

③ 최종 값은 3,000


위 경우로만 보면 Current 모드로 갱신하는 것이 매우 이상적으로 보이지만 여기에도 맹점은 있다.

아래의 경우를 보자.


* T: 1~100,000 까지의 Unique한 번호를 가진 테이블

 TX1

 

 TX2

 UPDATE T SET NO = NO + 1

  WHERE NO > 50000;

t1

 

 

t2

 INSERT INTO T VALUES(100001,100001);

 

t3

 COMMIT;

 COMMIT;

t4

 

① 인덱스(no)를 경유해 순차적으로 UPDATE를 진행하는 경우

→ 50,001건이 UPDATE

② Full Table Scan 방식으로 UPDATE 진행하는 경우

→ 레코드가 INSERT 되는 위치에 따라 UPDATE 결과 건수가 달라짐

(이미 지나간 블록에 삽입된다면 50,000 건 UPDATE, 앞으로 지나갈 블록에 삽입된다면 50,001 건 UPDATE)

※ UPDATE나 DELETE 에 대해서도 위와 같은 현상이 일어날 수 있다.


Consistent 모드로 갱신대상을 식별하고, Current 모드로 갱신

- 실제 오라클이 UPDATE를 처리하는 방식


 TX1

 

 TX2

 UDPATE EMP SET SAL = SAL + 100

  WHERE EMPNO = 7788

    AND SAL = 1000;

t1

 

 

t2

 UDPATE EMP SET SAL = SAL + 200

  WHERE EMPNO = 7788

    AND SAL = 2000;

 COMMIT; 

t3

 

 

t4

 COMMIT; 


Consistent 모드에서 수행한 조건 체크를 Current 모드로 액세스하는 시점에 한 번 더 수행

Consistent 모드는 쿼리 시작 시점의 SCN을 기준으로 하기 때문에 UPDATE 대상이 되는 데이터들이 사실상 미리 정해지는 거라고 보면 이해가 쉽다. 

- 중간에 다른 세션에 의해 데이터가 INSERT 되어도 쿼리 시작 이후의 SCN이므로 UPDATE 대상이 아님

- 중간에 다른 세션에 의해 대상 데이터가 UPDATE 된다면 Current 모드로 액세스하는 시점에 한 번 더 조건 체크 할 때 제외 처리됨 


오라클에서 일관성 없게 값을 갱신하는 사례

* 스칼라 서브쿼리는 특별한 이유가 없는 한 항상 Consistent 모드로 읽기를 수행

UPDATE 계좌2

   SET 총잔고 = 계좌2.잔고 +

      (SELECT 잔고 FROM 계좌1 WHERE 계좌번호 = 계좌2.계좌번호)

 WHERE 계좌번호 = 7788;

-- 계좌2는 Current 모드, 계좌1은 Consistent 모드로 읽어 잘못된 결과를 도출할 수 있다.

UPDATE 계좌2

   SET 총잔고 = (SELECT 계좌2.잔고 + 잔고 FROM 계좌1 

          WHERE 계좌번호 = 계좌2.계좌번호)

 WHERE 계좌번호 = 7788;

-- Current 모드로 읽어야 할 계좌2.잔고를 스칼라 서브쿼리 내에서 참조하기 때문에 스칼라 서브쿼리까지도 Current 모드로 작동


너무 헷갈리면 "오라클은 Consistent 모드로 갱신대상을 식별하고, Current 모드로 갱신한다." 만 명심하도록 하자!

아.. 머리 아프~

by 정미나 2018.04.11 18:30