Oracle에서 BULK COLLECT INTO는 대량의 데이터를 한 번에 메모리에 로드하여 처리할 수 있는 방법을 제공합니다.
일반적으로 ROW BY ROW 방식으로 데이터를 처리하는 것보다 BULK COLLECT INTO 방식을 사용하는 것이 성능이 좋습니다.
그 이유는 다음과 같습니다.
네트워크 부하 감소 BULK COLLECT INTO를 사용하면 데이터베이스와 클라이언트 간의 네트워크 부하가 적어지기 때문에 성능이 향상됩니다. ROW BY ROW 방식은 데이터를 한 줄씩 읽어오기 때문에 많은 양의 데이터가 있을 경우 네트워크 부하가 커집니다.
메모리 사용 최적화 BULK COLLECT INTO를 사용하면 대량의 데이터를 한 번에 메모리에 로드하기 때문에 메모리 사용이 최적화됩니다. ROW BY ROW 방식은 매번 한 줄씩 메모리를 로드하기 때문에 메모리 사용이 많아질 수 있습니다.
수행 시간 감소 BULK COLLECT INTO를 사용하면 SQL문을 한 번 실행하여 결과를 한꺼번에 가져올 수 있기 때문에, ROW BY ROW 방식보다 수행 시간이 감소합니다.
하지만 BULK COLLECT INTO 방식은 메모리 사용량이 많아질 수 있으므로, 대량의 데이터를 처리할 때 메모리 사용량을 고려하여 적절한 크기로 나누어 처리해야 합니다.
이를 잘 제어하지 못하면 메모리를 과다하게 사용하여 오히려 성능이 나빠질 수도 있습니다.
SELECT COUNT(*) FROM KPI_FCSTACCURACY_AP1;
DECLARE
V_COUNT NUMBER := 1;
V_ITEM VARCHAR(50);
START_TIME NUMBER;
END_TIME NUMBER;
V_RESULT NUMBER;
BEGIN
---------- 1. 시작 시간 -----------------------
START_TIME := DBMS_UTILITY.GET_TIME;
----------------------------------------------
---------- 2. 로직 시작 -----------------------
FOR R IN (SELECT * FROM KPI_FCSTACCURACY_AP1)
LOOP
V_COUNT := V_COUNT+1;
END LOOP;
DBMS_OUTPUT.PUT_LINE(V_COUNT);
DBMS_OUTPUT.PUT_LINE(V_ITEM);
---------- 3. 종료 시간 및 소요시간 계산 ---------
END_TIME := DBMS_UTILITY.GET_TIME;
SELECT (END_TIME - START_TIME)/100 DIFF_SEC INTO V_RESULT FROM DUAL;
DBMS_OUTPUT.PUT_LINE(V_RESULT);
----------------------------------------------
END;
DECLARE
TYPE TABLE_REC IS TABLE OF KPI_FCSTACCURACY_AP1%ROWTYPE INDEX BY PLS_INTEGER;
CURSOR C_TABLE IS (SELECT * FROM KPI_FCSTACCURACY_AP1);
V_TABLE_ARR TABLE_REC;
V_COUNT NUMBER := 1;
V_ITEM VARCHAR(50);
START_TIME NUMBER;
END_TIME NUMBER;
V_RESULT NUMBER;
BEGIN
---------- 1. 시작 시간 -----------------------
START_TIME := DBMS_UTILITY.GET_TIME;
----------------------------------------------
---------- 2. 로직 시작 -----------------------
OPEN C_TABLE;
LOOP
FETCH C_TABLE BULK COLLECT INTO V_TABLE_ARR LIMIT 500;
EXIT WHEN V_TABLE_ARR.COUNT = 0;
FOR R IN V_TABLE_ARR.FIRST .. V_TABLE_ARR.LAST
LOOP
V_COUNT := V_COUNT+1;
END LOOP;
END LOOP;
DBMS_OUTPUT.PUT_LINE(V_COUNT);
CLOSE C_TABLE;
---------- 3. 종료 시간 및 소요시간 계산 ---------
END_TIME := DBMS_UTILITY.GET_TIME;
SELECT (END_TIME - START_TIME)/100 DIFF_SEC INTO V_RESULT FROM DUAL;
DBMS_OUTPUT.PUT_LINE(V_RESULT);
----------------------------------------------
END;
| FOR | BULK COLLECT INTO LIMIT 500 | BULK COLLECT INTO LIMIT 1000 | BULK COLLECT INTO LIMIT 1500 |
|---|---|---|---|
| 10.25초 | 10.79초 | 10.1초 | 10.18초 |
Oracle의 FORALL 문은 PL/SQL에서 대량의 데이터를 한 번에 처리할 수 있는 방법을 제공합니다. 이를 사용하면 성능이 향상됩니다.
그 이유는 다음과 같습니다.
한 번의 SQL문으로 대량의 데이터 처리 FORALL 문을 사용하면 한 번의 SQL 문으로 대량의 데이터 처리가 가능합니다. 이는 SQL 문이 실행될 때마다 데이터베이스와의 연결 및 트랜잭션 처리 시간이 줄어들어 성능이 향상됩니다.
바인드 변수를 사용하여 메모리 사용 최적화 FORALL 문은 바인드 변수를 사용하여 메모리 사용을 최적화합니다. 바인드 변수를 사용하면 SQL 문이 실행될 때마다 새로운 메모리 공간을 할당하지 않고, 이미 할당된 메모리 공간에 값을 할당합니다. 따라서 메모리 사용량도 줄어들어 성능이 향상됩니다.
하지만 FORALL 방식은 메모리 사용량이 많아질 수 있으므로, 대량의 데이터를 처리할 때 메모리 사용량을 고려하여 적절한 크기로 나누어 처리해야 합니다.
이를 잘 제어하지 못하면 메모리를 과다하게 사용하여 오히려 성능이 나빠질 수도 있습니다.
CREATE TABLE MOCK_TABLE
(
C1 NUMBER,
C2 NUMBER
);
DECLARE
START_TIME NUMBER;
END_TIME NUMBER;
V_RESULT NUMBER;
BEGIN
---------- 1. 시작 시간 -----------------------
START_TIME := DBMS_UTILITY.GET_TIME;
----------------------------------------------
---------- 2. 로직 시작 -----------------------
FOR i IN 1 .. 100000
LOOP
INSERT INTO MOCK_TABLE
VALUES (i, i);
END LOOP;
COMMIT;
---------- 3. 종료 시간 및 소요시간 계산 ---------
END_TIME := DBMS_UTILITY.GET_TIME;
SELECT (END_TIME - START_TIME) / 100 DIFF_SEC
INTO V_RESULT
FROM DUAL;
DBMS_OUTPUT.PUT_LINE (V_RESULT);
----------------------------------------------
END;
/
DECLARE
TYPE MOCK_TABLE_INS IS TABLE OF MOCK_TABLE%ROWTYPE
INDEX BY BINARY_INTEGER;
V_MOCK MOCK_TABLE_INS;
START_TIME NUMBER;
END_TIME NUMBER;
V_RESULT NUMBER;
BEGIN
---------- 1. 시작 시간 -----------------------
START_TIME := DBMS_UTILITY.GET_TIME;
----------------------------------------------
---------- 2. 로직 시작 -----------------------
FOR i IN 1 .. 100000
LOOP
V_MOCK (i).C1 := i;
V_MOCK (i).C2 := i;
END LOOP;
FORALL i IN 1 .. 100000
INSERT INTO MOCK_TABLE
VALUES V_MOCK (i);
COMMIT;
---------- 3. 종료 시간 및 소요시간 계산 ---------
END_TIME := DBMS_UTILITY.GET_TIME;
SELECT (END_TIME - START_TIME) / 100 DIFF_SEC
INTO V_RESULT
FROM DUAL;
DBMS_OUTPUT.PUT_LINE (V_RESULT);
----------------------------------------------
END;
/
| FOR WITH 100000 DATA | FORALL WITH 100000 DATA |
|---|---|
| 2.41초 | 0.14초 |