h1. 제3절 데이터베이스 Call과 네트워크 부하
1. 데이터베이스 Call 종류
2. 데이터베이스 Call 과 성능
3.Array Processing 활용
4. Fetch Call 최소화
5.페이지 처리 활용
6.분산 쿼리
7.사용자 정의 함수 / 프로시저의 특징과 성능
{panel:title=1. 데이터베이스 Call 종류
borderColor=#ccctitleBGColor=#B0C4DEbgColor=#ffffff}

가. SQL 커서에 대한 작업 요청에 따른 구분


1) Parse Call : SQL 파싱을 요청한느 Call
2) Execute Call : SQL 실행을 요청하는 Call
3) Fetch Call : SELECT 문의 결과 데이터 전송을 요청하는 Call

나. Call 발생 위치에 따른 구분


1) User Call

  • DBMS 외부로부터 요청되는 Call
  • User Call이 많으면 성능이 좋을수 없으므로 ,User Call을 최소화 하려는 노력이 중요
  • User Call을 줄이기 위한 기술요소
    1. Loop 쿼리를 해소하고 집합적 사고를 통해 One Sql로 구현
    2. Array Processing : Array 단위 Fetch, Bulk Insert/Update/Delete
    3. 부분범위처리 원리 활용
    4. 효과적인 화면 페이지 처리
    5. 사용자 정의 함수/프로시저/트리거의 적절한 활용

2)Recursive Call

  • DBMS 내부에서 발생하는 Call
  • SQL 파싱과 최적화 과정에서 발생하는 데이터 딕셔너리 조회, 사용자 정의함수/프로시저 내에서의 SQL수행
  • Recursive Call 최소화방안
    1. 바인드 변수를 사용하여 하드파싱 발생 횟수 감소
    2. 사용자 정의 함수/프로시저의 적절한 사용

2. 데이터베이스 Call 과 성능

가. One SQL 구현의 중요성

  • 루프를 돌면서 여러작업을 반복해서 수행하는 프로그램(JAVA,C,VB,Delphi등)을 One SQL로 구현했을 때 데이터베이스 콜횟수를 줄여 성능 개선 효과
  • DBMS 내에서 수행되는 사용자 정의 프로시저로 개발하면 네트워크 트래픽없는 Recursive Call만 발생하므로 빠르게 수행됨
  • 데이터베이스 Call은 개별 프로그램의 수행속도에 큰 영향을 미칠 뿐만 아니라 시스템 전체의 확장성에 영향을 미친다.
    ex, 메소드를 5번 호출해서 parse cll과 execute call이 각각 5번 발생하는 하는 프로그램이 24시간돈다고 할 때 메소드를 1번만 호출하게 수정해주면 시스템이 5배의 확장성을 갖는것

3.Array Processing 활용

  • Array Processing 기능을 활용하면 한번의 SQL(INSERT/UPDATE/DELETE)수행으로 다량의 레코드를 동시처리가능
  • 네트워크 Call 감소, SQL 수행시간, CPU 사용량 감소
  • Array에 담아 한꺼번에 처리를 하면 Call횟수를 줄이게 되어 성능개선에 도움
  • Array Processing 기법을 지원하는 인터페이스가 개발 언어마다 다르므로 API를 통해 반드시 확인하고 활용해야 함

4. Fetch Call 최소화

가. 부분범위처리 원리

  • 쿼리 결과 집합을 전송할때, 전체 데이터를 연속적으로 전송하지 않고 사용자로부터 Fetch Call이 있을때마다 일정량씩 나누어서 전송하는 것
  • 데이터를 클라이언트에게 전송할 때 일정량씩 나누어서 전송

set arraysize 100
call  count cpu   elapsed disk query current rows
----- ----- ----- ------- ----- ----- ----- ------
Parse     1 0.00    0.00     0     0     0     0
Execute   1 0.00    0.02     2     2     0     0
Fetch   301 0.14    0.18     9   315     0 30000
----- ----- ----- ------- ----- ----- ----- ------
total   303 0.14    0.20    11   317     0 30000


  • SQL Server : 쿼리분석기 옵션에 설정되어있는 "네트워크 패키지 크기"로 운반 (default 4,096 바이트)
  • ORACLE : 내부적으로는 SDU(Session Data Unit,Session 레이어), TDU(Transport Data Unit,Transport 레이어) 단위로 나누어서 전송
    array 사이즈를 작게 설정하면 하나의 네트워크 패킷에 담아 전송하겠지만, 크게 설정하면 여러개의 패킷으로 나누어 전송

나. ArraySize 조정에 의한 Fetch Call 감소 및 블록 I/O 감소 효과

  • 대량의 데이터파일을 전송한다면 arraysize 크게하여 fetch call 횟수를 줄여주는것이 유리
  • 반대로 적은량의 데이터만 fetch 하다가 멈추는 프로그램이라면 arraysize를 작게 설정하는것이 유리
  • arraysie를 증가시키면 네트워크 부하감소 및 서브프로세스가 읽어야할 블록 갯수 감소 효과
ArraySizeFetch 횟수블록I/O
31012
1033
3011

  • ArraySize와 Fetch Count 및 블록 I/O 관계 : 반비례
  • ArraySize 를 키운다고 해서 Fetch count 와 블록 I/O가 같은 비율로 줄지 않음
  • ArraySize를 무작정 크게 설정한다고 좋은것이 아니며, 일정크기 이상이면 리소스만 낭비하는 결과를 초래할 수 있음

# SQL*Plus 이외의 프로그램 언어에서 Array 단위 Fetch 기능 활용 방법*

1) Oracle PL/SQL(커서를 열고 레코드를 Fetch)
-9i : 한번에 한 로우씩만 처리(Single-Row Fetch)
-10g : 자동으로 100개씩 array Fetch가 일어남. (Cursor For Loop 구문을 이용할때만 작동)


for item in cursor
loop
   ......
end loop;

2) JAVA(FetchSize를 100으로 설정했을때 데이터를 Fetch 해오는 매커니즘)


String sql = "select custid, name from customer";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setFetchSize(100); -- Statement에서 조정

ResultSet rs = stmt.executeQuery();
// rs.setFetchSize(100); -- ResultSet에서 조정할 수도 있다.

while( rs.next() ) {
  int empno = rs.getInt(1);
  String ename = rs.getString(2);
  System.out.println(empno + ":" + ename);
}

rs.close();
stmt.close();

1. 최초 rs.next() 호출 시 한꺼번에 100건을 가져와서 클라이언트 Array 버퍼에 캐싱한다.
2. 이후 rs.next() 호출할 때는 데이터베이스 Call을 발생시키지 않고 Array 버퍼에서 읽는다.
3. 버퍼에 캐싱 돼 있던 데이터를 모두 소진한 후 101번째 rs.next() 호출 시 다시 100건을 가져온다.
4. 모든 결과집합을 다 읽을 때까지 2~3번 과정을 반복한다.

5.페이지 처리 활용

  • 페이지 처리를 하지 않을때 발생하는 부하요인
    1. 다량 발생하는 Fetch Call의 부하
    2. 대량의 결과 집합을 클라이언트에 전송하면서 발생하는 네트워크 부하
    3. 대량의 데이터 블록을 읽으면서 발생하는 I/O 부하
    4. AP 서버 및 웹 서버 리소스 사용량 증가
  • 페이지처리를 통한 부하해소
    1. 페이지 단위로, 화면에서 필요한 만큼만 Fetch Call
    2. 페이지 단위로, 화면에서 필요한 만큼만 네트워크를 통해 결과 전송
    3. 인덱스와 부분범위처리 원리를 이용해 각 페이지에 필요한 최소량만 I/O
    4. 데이터를 소량씩 나누어 전송하므로 AP웹 서버 리소스 사용량 최소화
  • 조회할 데이터가 일정량 이상이고 수행빈도가 높다면 필수적으로 페이지 처리 구현해야함

6.분산 쿼리


분산 DB간 테이블 조인


select channel_id, sum(quantity_sold) auantity_cold
from order a, sales@lk_sales b
where a.order_date between :1 and :2
and b.order_no = a.order no
group by channel_id

Rows    Row Source Operation
-----   ---------------------------------------------
5 SORT  GROUP BY
10981    NESTED LOOPS
500000    REMOTE
10981     TABLE ACCESS BY INDEX ROWID ORDER
500000     INDEX UNIQUE SCAN (ORDER_PK)

  • 원격의 lk_sales l테이블을 전송받아 order 테이블과 NL 조인
  • 50만건이나 되는 데이터를 네트워크를 통해 전송받고 있어 성능저하의 원인이 됨.

분산 DB 간의 성능저하 해결방안


select /*+ driving_site(b) */ channel_id, sum(quantity_sold) auantity_cold
from order a, sales@lk_sales b
where a.order_date between :1 and :2
and b.order_no = a.order_no
group by channel_id
Rows   Row Source Operation
----   ---------------------------------------------
5 SORT GROUP BY
10981   NESTED LOOPS
939      TABLE ACCESS (BY INDEX ROWID) OF 'ORDER'
939       INDEX (RANGE SCAN) OF 'ORDER_IDX2' (NON-UNIQUE)
10981    REMOTE

  • order_date에 조건에 해당하는 데이터만 원격으로 보내서 조인과 group by를 거친 결과 집합만 전송받음
  • 원격서버가 처리가능하도록 dirving_site 힌트 사용

분산쿼리의 성능을 높이는 핵심은, 네트워크를 통한 데이터 전송량을 줄이는 데 있다

7.사용자 정의 함수 / 프로시저의 특징과 성능

가.사용자 정의 함수/프로시저의 특징

  • 내장함수처럼 Native 코드로 완전 컴파일된 형태가 아니어서 가상머신과 같은 별도의 실행엔진을 통해 실행됨
  • 실행시마다 컨텍스트 스위칭이 일어나므로, 내장함수를 호출할때와 비교해서 성능이 상당히 떨어짐
  • 예시)문자타입의 일자 데이터를 날짜 타입으로 변환해주는 사용자정의함수

create or replace function date_to_char(p_dt date) return varchar2 as
  begin
    return to_char(p_dt, 'yyyy/mm/dd hh24:mi:ss');
  end;
/

=> to_char 함수를 바로 호출할때보다 훨씬 느림

  • 메인쿼리가 참조하는 사용자 정의 함수에 또 다른 쿼리문이 내장되어 있다면 수행 성능이 훨씬 나빠짐
  • 함수에 내장된 쿼리를 수행할 때마다 Execute Call, Fetch Call이 재귀적으로 일어남.
  • Recusive Call이 반복적으로 일어남(User Call 에 비해 성능부하가 미미하지만, 그 횟수가 무수히 반복되면 성능 저하)

나.사용자 정의 함수/프로시저에 의한 성능 저하 해소 방안

  • 소량의 데이터를 조회할 때 사용
  • 부분점위 처리가 가능한 상황에서 제한적으로 사용
  • 가급적 함수를 풀어 조인 또는 스칼라 서브쿼리 형태로 변환

|