2016-10-29 2 views
0

대량 수집을 작성하는 데 더 좋고 선호되는 방법이 있는지 궁금합니다. 나는 다른 접근을 본 적이 일부는 아래의 샘플 코드에 있습니다대량 수집을위한 최상의 구문

set serveroutput on; 
declare 

    cursor ext_data_file is 
    select * 
    from PER_ALL_PEOPLE_F; 

    TYPE type_emp_rec_ext IS TABLE OF ext_data_file%ROWTYPE index by pls_integer; 

    l_emp_tab_ext_raw   type_emp_rec_ext; 
    l_emp_tab_ext_clean  type_emp_rec_ext; 
    l_start     number; 
    l_count     number := 0; 
    l_count2     number := 0; 

begin 

    /* Regular Cursor Fetch */ 

    l_start := DBMS_UTILITY.get_time; 

    FOR cur_rec IN ext_data_file LOOP 
     l_count2 := l_count2 + 1; 
    END LOOP; 

    DBMS_OUTPUT.put_line('Regular (' || l_count2 || ' rows): ' || (DBMS_UTILITY.get_time - l_start) ||' ms'); 

    /* Bulk Collect 1 */ 

    l_start := DBMS_UTILITY.get_time; 

    open ext_data_file; 
    fetch ext_data_file 
    bulk collect 
    into l_emp_tab_ext_raw; 
    close ext_data_file; 

    DBMS_OUTPUT.put_line('Bulk 1 (' || l_emp_tab_ext_raw.count || ' rows): ' || (DBMS_UTILITY.get_time - l_start) ||' ms'); 

    /* Bulk Collect 2 */ 

    l_start := DBMS_UTILITY.get_time; 

    SELECT * 
    BULK COLLECT INTO 
    l_emp_tab_ext_clean 
    FROM PER_ALL_PEOPLE_F; 

    DBMS_OUTPUT.put_line('Bulk 2 (' || l_emp_tab_ext_raw.count || ' rows): ' || (DBMS_UTILITY.get_time - l_start) ||' ms'); 

    /* Bulk Collect 3 */ 

    l_start := DBMS_UTILITY.get_time; 

    OPEN ext_data_file; 
    LOOP 
     FETCH ext_data_file 
     BULK COLLECT INTO l_emp_tab_ext_raw LIMIT 1000;  
     l_count := l_emp_tab_ext_raw.count + l_count; 
     EXIT WHEN l_emp_tab_ext_raw.count = 0;   
    END LOOP; 
    CLOSE ext_data_file; 

    DBMS_OUTPUT.put_line('Bulk 3 (' || l_count || ' rows): ' || (DBMS_UTILITY.get_time - l_start) ||' ms'); 

EXCEPTION 
    WHEN OTHERS THEN 
     dbms_output.put_line(sqlerrm); 
end; 

는 성능면에서, 나는 변화를보고 놀랐습니다. Regular Fetch는 Bulk Collects보다 빠릅니다! 위의 관찰이 올바른지

Bulk Collect 1 : Commonly used when using an Explicit Cursor and has no LIMIT Clause. Also when the cursor Involves numerous Joined Tables. 
Bulk Collect 2 : Commonly used when using a single table or an Implicit Cursor and has no LIMIT Clause. 
Bulk Collect 3 : Commonly used when using an Explicit Cursor and has a LIMIT Clause. 

가 친절하게 확인 : 여기
Regular (1202666 rows): 4174 ms 
Bulk 1 (1202666 rows): 6369 ms 
Bulk 2 (1202666 rows): 7204 ms 
Bulk 3 (1202666 rows): 4380 ms 

내 관측이다.

1. Why is the Regular Fetch Faster? 
2. Which of these Bulk Collects are the Best Syntax to Use in Terms of Overall Performance and Memory Consumption) 

난 항상 구문 1 사용하고있다,하지만 난 최선이 구문 3.

데이터베이스 세부 사항입니다 생각한다 :

그리고 내 질문은

Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production 
PL/SQL Release 11.2.0.4.0 - Production 
CORE 11.2.0.4.0 Production 
TNS for Solaris: Version 11.2.0.4.0 - Production 
NLSRTL Version 11.2.0.4.0 - Production 

감사합니다!

답변

1

왜 대량 수집없이 더 빠릅니까? 커서에서 가져온 데이터에 대해 아무런 작업도 수행하지 않기 때문입니다. 일반적으로 데이터를 업데이트/삽입 할 때 행별로 행을 일괄 처리하지 않고 대량 처리를 수행합니다. 해당 행을 다른 테이블에 삽입하여 루프에서 실행하려고하면 차이가 나타납니다.

어느 쪽이 더 낫습니까? 요구 사항에 따라 다릅니다. 나에게 가장 의미있는 것은 한계가있는 해결책을 만든다. 1 및 2와 같이 전체 데이터 세트를 처리해야하는 이유는 무엇입니까? 이는 아마도 내가 방대한 성명서에서 데이터를 처리 할 수 ​​있었다는 것을 의미합니다. 제한을 사용할 경우 데이터 처리의 최상의 성능을 얻기 위해 배치 크기를 최적화 할 수 있습니다. 또한 삽입 속도와 삽입/업데이트중인 테이블 잠금 시간간에 절충안을 찾는 데에도 한계가 있습니다.

+0

고마워요! 나는 이것도 어느 ​​정도 대답한다고 생각한다. 질문 1 [링크] (https://oracle-base.com/articles/9i/bulk-binds-and-record-processing-9i) "Oracle 10g부터 최적화 된 PL/SQL 컴파일러는 cursor FOR LOOP를 배열 크기가 100 인 BULK COLLECT로 변환합니다. " –

관련 문제