배열처리 (Host Arrays)

 

배열로 처리하는 것의 장점

    Host 변수에 배열을 넘긴다는 것은 한번에 여러건을 동시에 처리한다는 의미입니다. 여러건을 동시에 처리하는 것의 장점은 DBMS와의 통신 횟수를 줄입니다. 통신 횟수가 줄어들면 데이터 처리에 대한 성능이 많이 개선됩니다. 예를들면 10,000건 데이터를 INSERT해야 하는 데, 건별로 처리하면 10,000번 이상의 데이터 전송과 수신이 일어납니다. 그러나 1,000건 단위로 배열로 처리한다면, 10번의 송수신으로 끝납니다. 특히, 시스템간의 네트워크 구간이 느린 경우에는 많은 성능의 차이가 발생할 수 있습니다.

 

Host 변수를 배열로 선언할 때 주의사항

- char와 VARCHAR type을 제외하고 모든 변수는 단일배열로 선언해야 합니다.

- char와 VARCHAR type은 2중배열로 선언해야 합니다.

- 함께 사용할 배열은 배열의 크기가 다를 경우 가장 작은 배열의 크기로 처리됩니다.

 

Host 변수 잘못 선언한 배열 예)

    long emp_number[50][50];  // 이중 배열 선언
    int   age[50][30];        // 이중 배열 선언
    VARCHAR name[50];         // 단일 배열 선언
    char data[50]             // 단일 배열 선언

 

Host 변수 올바르게 선언한 배열 예)

    long emp_number[50];
    VARCHAR name[50][32];
    int  age[50];

 

아래의 배열 변수를 함께 사용하면 최대크기는 25가 됩니다.

    int emp_number[50];
    char emp_name[50][10];
    int dept_number[25]; 

 


INPUT 배열의 사용(처리)

INPUT 배열은 INSERT / UPDATE / DELETE에 사용하며, 다 건 처리를 위한 용도로 사용하며 실제로 처리된 건수는 slqca.sqlerrd[2] 변수에 저장됩니다. 그리고 설정된 Array Size에 맞게 데이터를 항상 채워서 실행할 수 없는 경우도 있기 때문에 FOR절을 추가하여 처리할 건수를 지정하는 것이 좋습니다. FOR절이 없으면 Array Size만큼 데이터가 full로 입력되었다는 것을 의미합니다.

 

Example)

    int    emp_number[50];
    char emp_name[50][10];
    int    dept_number[50];
    int   insert_size;          // 배열을 50으로 잡았지만 실제로 처리할 배열 건수

    // 배열에 데이터를 채우는 로직...

    ......
    
    insert_size = 32;     // 처리할 데이터가 32건 밖에 없음.

    EXEC SQL FOR :insert_size INSERT INTO emp (empno, ename, deptno)
    VALUES (:emp_number, :emp_name, :dept_number);

    if(sqlca.sqlcode != 0) {
        fprintf(stderr, "INSERT ERROR: %.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }

    // 처리건수는 sqlca.sqlerrd[2]에 저장됩니다.
    printf("%d건이 INSERT되었습니다.\n", slqca.sqlerrd[2]); 

 

Example). Indicator를 사용하는 예제

    int       emp_number[50];
    int       dept_number[50];
    double    commission[50];
    short     comm_ind[50];   /* indicator array */
    int       insert_size;    // 배열을 50으로 잡았지만 실제로 처리할 배열 건수

    // 배열에 데이터를 채우는 로직...

    ......
    
    insert_size = 32;     // 처리할 데이터가 32건 밖에 없음.

    EXEC SQL FOR :insert_size INSERT INTO emp (empno, deptno, comm)
    VALUES (:emp_number, :dept_number,  :commission INDICATOR :comm_ind); 

    if(sqlca.sqlcode != 0) {
        fprintf(stderr, "INSERT ERROR: %.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }

    // 처리건수는 sqlca.sqlerrd[2]에 저장됩니다.
    printf("%d건이 INSERT되었습니다.\n", slqca.sqlerrd[2]); 

처리 건수를 설정하는 FOR절에는 host 변수를 사용합니다. 사칙연산 등의 연산자가 올 수 없습니다.

 

Example). 잘못 사용한 예

    EXEC SQL FOR :rows_to_insert + 5     /* illegal */
    INSERT INTO emp (ename, empno, sal)
    VALUES (:emp_name, :emp_number, :salary);    

 


OUTPUT 배열 사용하기 (조회)

  SELECT문은 배열로 INPUT을 사용할 수 없으며, 조회한 결과(OUTPUT)가 배열로 받을 수 있습니다. SELECT문이나 SELECT ~ FETCH문에도 fetch할 Array Size를 설정할 수 있습니다. INTO 절이 있는 곳에 사용합니다. 

EXEC SQL FOR :fetch_size  ~ INTO ~

조회의 경우에는 일반적으로 FOR절을 사용하지 않습니다. INSERT/UPDATE/DELETE는 INPUT이라 몇 건인지 알고 사용하지만, SELECT의 경우는 OUTPUT이라 몇 건이 올지 모르기 때문에 지정하지 않고 최대 Array size만큼 받습니다.

 

Example) SELECT

    char emp_name[50][20];
    int   emp_number[50];
    long salary[50];

    EXEC SQL FOR :fetch_size SELECT ENAME, EMPNO, SAL
    INTO :emp_name, :emp_number, :salary
    FROM EMP
    WHERE SAL > 1000;

    if(sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) {
        fprintf(stderr, "조회 ERROR: %.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }

    // 조회건수는 sqlca.sqlerrd[2]에 저장됩니다.
    printf("%d건이 조회되었습니다.\n", slqca.sqlerrd[2]); 

 

Example). SELECT ~ FETCH

    int  emp_number[100];
    char emp_name[100][20];
    int  total_count, row_count;
    int  idx;

    EXEC SQL DECLARE emp_cursor CURSOR FOR
    SELECT empno, ename
    FROM emp
    WHERE deptno = 30;

    EXEC SQL OPEN emp_cursor;

    total_count = 0; /* 이전까지 누계 건수 */

    while(1) {
        EXEC SQL FOR :fetch_size FETCH emp_cursor
        INTO :emp_number, :emp_name;

        if(sqlca.sqlcode != 0 && sqlca.sqlcode != 1403) {
            fprintf(stderr, "FETCH ERROR: %.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
            return -1;
        } 

        row_count = sqlca.sqlerrd[2] - total_count;
        total_count = sqlca.sqlerrd[2];

        for(idx = 0; idx < row_count; idx++) {
            printf("%d - %s\n", emp_number, emp_name);
        }

        if(sqlca.sqlcode == 1403) { 
            /* 1403(DATA NOT FOUND)는 Array 크기만큼 다 차지않았을 때에도 발생함.*/
            break;
        }
    } 

 

 

 

See Also : Pro*C 목차 및 Sample Source

 

 

 

 

'Oracle > Pro*C' 카테고리의 다른 글

Pro*C 목차 및 Sample Source  (0) 2019.09.25
Pro*C 7. Dynamic SQL  (0) 2019.09.25
Pro*C 6. 대량처리 (배열처리)  (0) 2019.09.25
Pro*C 5-2. 오류 처리하기 (WHENEVER)  (0) 2019.09.25
Pro*C 5-1. 오류 처리하기 (SQLCA)  (0) 2019.09.25
Pro*C 4. 기본 SQL문 실행  (0) 2019.09.25
블로그 이미지

사용자 자연&사람

행복한 개발자 programmer since 1995.

Tag , , ,

댓글을 달아 주세요