데이터베이스 애플리케이션 개발 방법
오라클 아키텍처의 이해
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: 이 트랜잭션에 대한 직렬화 액세스를 할 수 없습니다