1. 시스템이 3대면 최대 process 수는 150 * 3 = 450 인가요?
--> 이론적으로는 그렇지만...(정상적인 서비스의 상황일때...)
사실은 고려해야 하는 사항들이 있습니다.
특별이 로드밸런싱 없이 VIP통해 서비스 한다면 각 노드가 랜덤하게 세션을 받기때문에
한쪽 노드에 세션이 몰릴 수 있는 가능성도 있습니다.
(그래서 9i에서는 업부별 노드접속 파티셔닝을 하는 경우도 있었습니다.)
그리고 1개 또는 2개의 노드가 down되는 최악의 경우 나머지 노드가 모든 세션을 감당해야 하므로
실제 설정해야 하는 최대 process는 조금더 높게 잡으셔야 합니다.
select * from v$resource_limit;
로 노드별 process의 MAX_UTILIZATION를 모니터링하면서 세개노드를 합한 값을
각 노드의 process 파라미터값으로 결정하시면 됩니다.
2. 시스템이 3대 각 8G memory 면 얼마정도 까지 잡아줘야 할까요?
--> SGA 크기에 따라 서버에서 실행되는 어플리케이션에 따라 적당히 결정.... ㅡㅡ;
top, topas, nmon등으로 확인했을 때의 메모리 사용량은 SGA를 쓰는것으로 알고 있습니다.
(이건 확실하지 않으므로 한번 확인해 보시기 바랍니다.)
한 세션이 실제 OS상에서 차지하는 메모리량을 계산하는 방법을 메타링크에서 본적이 있는데
기억이 나지 않는군요. 보통은 2~3MB 내외입니다.
용도에 맞게 설정하시고... 시스템 메모리가 많이 남는다고 해서 굳이 꽉꽉 채워서 설정할 필요까지는 없습니다.
select segment_type,segment_name,tablespace_name,to_char(round(bytes/1024/1024,1),'9,999,999') "MBytes"
from user_segments
where segment_type = 'TABLE'
order by segment_type,segment_name;
SELECTS문에서 한번에 대량의 레코들 취득 하는 경우, BULK COLLECT구를 사용하면
한번에 여러개의 레코드를 취득할수 있으므로 퍼포먼스 향상
Patten 1
DECLARE
TYPE empno_tbl_type IS TABLE OF EMP.EMPNO%TYPE INDEX BY BINARY_INTEGER;
empno_tbl empno_tbl_type;
BEGIN
SELECT EMPNO BULK COLLECT INTO empno_tbl FROM EMP;
IF empno_tbl.COUNT > 0 THEN
FOR i IN empno_tbl.FIRST..empno_tbl.LAST LOOP
UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = empno_tbl( i );
END LOOP;
END IF;
END;
/
Patten 2
DECLARE
TYPE emp_tbl_type IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER;
emp_tbl emp_tbl_type;
BEGIN
SELECT * BULK COLLECT INTO emp_tbl FROM EMP;
IF emp_tbl.COUNT > 0 THEN
FOR i IN emp_tbl.FIRST..emp_tbl.LAST LOOP
UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = emp_tbl( i ).EMPNO;
END LOOP;
END IF;
END;
/
Patten 3 커서 이용
DECLARE
CURSOR emp_cur IS
SELECT * FROM EMP;
TYPE emp_tbl_type IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;
emp_tbl emp_tbl_type;
BEGIN
OPEN emp_cur;
FETCH emp_cur BULK COLLECT INTO emp_tbl;
CLOSE emp_cur;
IF emp_tbl.COUNT > 0 THEN
FOR i IN emp_tbl.FIRST..emp_tbl.LAST LOOP
UPDATE EMP SET SAL = SAL * 1.05 WHERE EMPNO = emp_tbl( i ).EMPNO;
END LOOP;
END IF;
END;
/
즉,커서를 이용할시 취득할 데이터 수가 많을듯하면 Limit를 사용하여 일정 레코드 단위로
Fetch하는 것이 성능면에서 좋다.
FETCH emp_cur BULK COLLECT INTO emp_tbl LIMIT 100;
rem -----------------------------------------------------------------------
rem Filename: bulkbind.sql
rem Purpose: Simple program to demonstrate BULK COLLECT and BULK BIND.
rem Notes: Bulk operations on ROWTYPE only work from and above.
rem Date: 12-Feb-2004
rem Author: Frank Naude, Oracle FAQ
rem -----------------------------------------------------------------------
set serveroutput on size 50000
DECLARE
CURSOR emp_cur IS SELECT * FROM EMP;
TYPE emp_tab_t IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
emp_tab emp_tab_t; -- In-memory table
rows NATURAL := 10000; -- Number of rows to process at a time
i BINARY_INTEGER := 0;
BEGIN
OPEN emp_cur;
LOOP
-- Bulk collect data into memory table - X rows at a time
FETCH emp_cur BULK COLLECT INTO emp_tab LIMIT rows;
EXIT WHEN emp_tab.COUNT = 0;
FOR i IN emp_tab.FIRST .. emp_tab.LAST loop
-- Manipumate data in the memory table...
dbms_output.put_line('i = '||i||', EmpName='||emp_tab(i).ename);
END LOOP;
-- Bulk bind of data in memory table...
FORALL i in emp_tab.FIRST..emp_tab.LAST
INSERT /*+APPEND*/ INTO emp2 VALUES emp_tab(i);
-- Implicit Cursor를 사용하는 경우
@ukja102
@mysid
@mon_on &v_sid
begin
for r in (select * from t1) loop
null;
end loop;
end;
/
@mon_off
spool result1.txt
@mon_show
spool off
@ukja102
@mysid
@mon_on &v_sid
-- Explicit Cursor를 사용하는 경우
declare
cursor v_cursor is
select * from t1
;
v_rec v_cursor%rowtype;
begin
open v_cursor;
loop
fetch v_cursor into v_rec;
exit when v_cursor%notfound;
end loop;
close v_cursor;
end;
/
@mon_off
spool result2.txt
@mon_show
spool off
여기서 한가지 질문을 던진다.
성능을 어떻게 비교할 것인가?
불행하게도 많은 사람들이 시작시간과 끝시간을 재는 것으로 만족한다. 그러지 말자.
Oracle은 성능을 비교하기 위한 많은 뷰들을 제공한다. 이들을 잘 활용해야 한다.
우선 v$sess_time_model 뷰를 통해 Time 정보를 비교한다. 이 뷰를 이용하면 별도의 코드를 통해 시간을 측정하지 않아도 된다.
sql execute elapsed time 25,827 6,044,618 6,018,791
DB CPU 29,331 6,034,029 6,004,698
PL/SQL execution elapsed time 60 558,753 558,693
parse time elapsed 1,509 131,440 129,931
-- Implicit Cursor를 사용한 경우
STAT_NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
DB time 59,773 1,777,125 1,717,352
sql execute elapsed time 40,140 1,721,534 1,681,394
DB CPU 51,929 1,683,972 1,632,043
parse time elapsed 42,324 256,573 214,249
-- Explicit Cursor를 사용한 경우
STAT_NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
DB time 29,622 6,051,808 6,022,186
sql execute elapsed time 25,827 6,044,618 6,018,791
DB CPU 29,331 6,034,029 6,004,698
PL/SQL execution elapsed time 60 558,753 558,693
parse time elapsed 1,509 131,440 129,931
Implicit Cursor가 모든 면에서 Explicit Cursor에 비해 현격한 성능 우위를 보이는 것을 알 수 있다.
그 이유가 무엇인지 가장 쉽게 알 수 있는 방법은? Statistics을 봐야 한다. v$sesstat 뷰를 통해 본 차이는 다음과 같다.
session pga memory max 1,498,708 1,891,924 393,216
session pga memory 1,498,708 1,891,924 393,216
session uga memory max 1,151,372 1,413,336 261,964
session logical reads 72 200,261 200,189
-- Implicit Cursor인 경우
NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
table scan rows gotten 62 914,002 913,940
session pga memory max 1,826,388 2,154,068 327,680
session uga memory max 1,282,300 1,544,264 261,964
session pga memory 1,826,388 1,957,460 131,072
session logical reads 275 3,249 2,974
-- Explicit Cursor인 경우
NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
table scan rows gotten 62 69,366,045 69,365,983
session pga memory max 1,498,708 1,891,924 393,216
session pga memory 1,498,708 1,891,924 393,216
session uga memory max 1,151,372 1,413,336 261,964
session logical reads 72 200,261 200,189
차이가 무엇인가?
놀랍게도 일량(Reads)의 차이가 절대적이라는것을 알 수 있다. logical reads가 10배 정도 차이나며 그 차이로 인해 성능의 차이가 왔다.
이 차이는 어디서 온 것인가?
Fetch Array Size에서 온 것이다. 한번에 많은 로우를 Fetch하면 Block을 방문해야할횟수가 줄어들며 그만큼 Logical Reads가 줄어든다. Implicit Cursor를 사용하는 경우에 Oracle은 내부적으로 10개를 한번에 Fetch한다. 반면에 Explicit Cursor를 사용하는 경우에는 한번에 한 개의 Row만 Fetch한다. 그 결과로 Logical Reads가 대략 10배의 차이가 나게 된다. 그 만큼 성능이 느린 것이다.
Explicit Cursor를 Implicit Cursor보다 빠르게 하는 유일한 방법은 Bulk Collection을 사용하는 것이다. 아래와 같이...
fetch v_cursor bulk collect into c1t, c2t; -- Do it bulk!!!
close v_cursor;
end;
/
@mon_off
spool result3.txt
@mon_show
spool off
@ukja102
@mysid
@mon_on &v_sid
declare
cursor v_cursor is
select * from t1
;
type c1tab is table of t1.c1%type;
type c2tab is table of t2.c2%type;
c1t c1tab;
c2t c2tab;
begin
open v_cursor;
fetch v_cursor bulk collect into c1t, c2t; -- Do it bulk!!!
close v_cursor;
end;
/
@mon_off
spool result3.txt
@mon_show
spool off
sql execute elapsed time 24,547 1,493,775 1,469,228
PL/SQL execution elapsed time 59 5,512 5,453
parse time elapsed 1,302 4,793 3,491
-- Implicit Cursor를 사용한 경우
STAT_NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
DB time 59,773 1,777,125 1,717,352
sql execute elapsed time 40,140 1,721,534 1,681,394
DB CPU 51,929 1,683,972 1,632,043
parse time elapsed 42,324 256,573 214,249
-- Explicit Cursor + Bulk Collection을 사용한 경우
STAT_NAME VALUE1 VALUE2 DIFF
---------------------------------------- ------------ ------------ ------------
DB time 28,024 1,503,542 1,475,518
DB CPU 18,620 1,489,167 1,470,547
sql execute elapsed time 24,547 1,493,775 1,469,228
PL/SQL execution elapsed time 59 5,512 5,453
parse time elapsed 1,302 4,793 3,491
Bulk Collection과 함께 Explicit Cursor를 사용한 경우 오히려 성능이 더 뛰어나다. 그 이유는?