데이터베이스 애플리케이션 개발 방법

오라클 아키텍처의 이해

  • 바인드 변수 사용.
    • 성능 문제.
    • sql injection 방어.

create table t (x int );

exec runstats_pkg.rs_start;

begin
    for i in 1 .. 10000
    loop
        execute immediate
        'insert into t values ( :x  )' using i;
    end loop;
end;
/

exec runstats_pkg.rs_middle;

begin
    for i in 1 .. 10000
    loop
        execute immediate
        'insert into t values ( ' || i || ' )';
    end loop;
end;
/

exec runstats_pkg.rs_stop(10000);

Run1 ran in 46 hsecs
Run2 ran in 398 hsecs
run 1 ran in 11.56% of the time

Name                                  Run1        Run2        Diff
STAT...consistent gets from ca          81      10,283      10,202
STAT...consistent gets from ca         130      10,349      10,219
STAT...consistent gets                 130      10,349      10,219
STAT...db block gets                10,436      30,366      19,930
STAT...db block gets from cach      10,436      30,366      19,930
LATCH.enqueue hash chains               78      20,037      19,959
STAT...db block gets from cach          75      20,037      19,962
STAT...recursive calls              10,075      40,203      30,128
STAT...session logical reads        10,566      40,715      30,149
LATCH.shared pool simulator             12      38,940      38,928
LATCH.cache buffers chains          51,559     111,726      60,167
STAT...session uga memory          130,976     196,464      65,488
LATCH.row cache objects                278     240,162     239,884
STAT...session pga memory          524,288     196,608    -327,680
LATCH.shared pool                   20,131     441,033     420,902
STAT...logical read bytes from  86,556,672 333,537,280 246,980,608

Run1 latches total versus runs -- difference and pct
Run1        Run2        Diff       Pct
73,439     854,305     780,866      8.60%

동시성 제어의 이해

  • 락이 무엇인지 데이터베이스 안에서 어떻게 동작하는지를 이해하는 것은 확장성 있는 정확한 애플리케이션을 개발하는 데 필수적이다.
  • DBMS마다 락킹의 방식이 다르다. 개발하는 DBMS의 락 방식을 이해하라.
  • 오라클의 락 정책
    • 데이터를 수정할 때 로우 레벨 락을 사용한다. 블록이나 테이블 레벨로 락이 확장하는 경우는 없다.
    • 데이터를 단순히 읽을 때는 락을 사용하지 않는다.
    • 데이터 쓰기 작업은 데이터 읽기 작업을 가로막지 않는다. (읽기가 쓰기에 의해 락이 걸리는 많은 다른 데이터베이스와 다른 근본적인 차이점)
    • 데이터 쓰기는 오직 이미 락이 걸리 로우에 대하여 또 다른 쓰기를 실행하려 할 때에만 차단한다.
  • 멀티버저닝 - 다중 버전, 일기 일관성 모델을 기본으로 제공하는 기능
    • 일기 일관성 쿼리 - 각 시점별로 일관된 결과를 추출한다.
    • NON-BLOCKING 쿼리 - 다른 데이터 베이스와는 달리, 읽기 처리는 쓰기 처리에 의해 절대 블로킹 되지 않는다.

drop table t purge;

create table t
as
select level lvl, 'text ' || level txt from dual
connect by level <= 5;

set autoprint off
variable x refcursor;
begin
    open :x for select * from t;
end;
/

declare
    pragma autonomous_transaction;
begin
    delete from t;
    commit;
end;
/

print x;

       LVL TXT
---------- ---------------------------------------------
         1 text 1
         2 text 2
         3 text 3
         4 text 4
         5 text 5         

  • 플래시백
    • 과거 오라클은 항상 쿼리 결과가 일관되도록 특별한 하나의 시점을 결정하였다.
      이런 결정은 오픈된 모든 결과집합이 최신의 데이터임을 보증하였는데, 다음 두가지 시점 중 하나가 적용된다.
      • 쿼리가 오픈된 시점 - READ COMMITED isolation 의 기본 동장
      • 쿼리가 속해 있는 트랜잭션이 시작되는 시점 - READ ONLY, SERIALIZABLE 레벨의 기본 동작이다.
    • 오라클 9i부터 'as of' 절을 통해서 과거 특정 시점 기준으로 쿼리를 실행할 수 있게 한다.(플래시백 쿼리)

var scn number;
exec :scn := dbms_flashback.get_system_change_number;
print scn;

select count(*) from emp;
delete from emp;
select count(*),
:scn then_scn,
dbms_flashback.get_system_change_number now_scn
from emp as of  scn :scn;

  COUNT(*)   THEN_SCN    NOW_SCN
---------- ---------- ----------
        14    1210733    1210739

commit;

select cnt_now, cnt_then,
:scn then_scn,
dbms_flashback.get_system_change_number now_scn
from (select count(*) cnt_now from emp),
(select count(*) cnt_then from emp as of  scn :scn);

   CNT_NOW   CNT_THEN   THEN_SCN    NOW_SCN
---------- ---------- ---------- ----------
         0         14    1210733    1210771

flashback table emp to scn :scn;
flashback table emp to scn :scn
                *
1행에 오류:
ORA-08189: 행 이동이 사용으로 설정되지 않았으므로 테이블을 플래시백할 수 없음

alter table emp enable row movement;

flashback table emp to scn :scn;

select cnt_now, cnt_then,
:scn then_scn,
dbms_flashback.get_system_change_number now_scn
from (select count(*) cnt_now from emp),
(select count(*) cnt_then from emp as of  scn :scn);

   CNT_NOW   CNT_THEN   THEN_SCN    NOW_SCN
---------- ---------- ---------- ----------
        14         14    1210733    1210884

데이터베이스 독립성(비의존성)

  • 데이터베이스들은 서로 다르다. 한 데이터베이스에서의 경험은 부분적으로 다른 데이터베이스에 도움이 되지만,
    근본적인 차이점뿐 아니라 아주 사소한 차이점에 대해서도 대비해야 한다.
  • 사소한 차이점(NULL 처리 방법)이 근본적인 차이점(동시성 제어 메커니즘 같은)만큼 큰 영향을 미칠 수 있다.
  • 데이터베이스가 어떻게 동작하고, 이러한 문제들을 해결하기 위해 어떤 기능들을 적용하고 있는지 알아야 한다.

-- 시퀀스 예
create table id_table
( id_name varchar2(30) primary key,
  id_value number);

insert into id_table values('my_key', 0);

update id_table
set id_value = id_value + 1
where id_name = 'my_key';

select id_value
from id_table
where id_name = 'my_key';
 
  ID_VALUE
----------
         1

-- session #1
set transaction isolation level serializable;

update id_table
set id_value = id_value + 1
where id_name = 'my_key';

select id_value
from id_table
where id_name = 'my_key';
 
  ID_VALUE
----------
         2
         
-- session #2
set transaction isolation level serializable;

update id_table
set id_value = id_value + 1
where id_name = 'my_key';

-- session #1
commit;

-- session #2
update id_table
*
1행에 오류:
ORA-08177: 이 트랜잭션에 대한 직렬화 액세스를 할 수 없습니다