Bulk Collect로 쿼리 효율성 향상

Oracle8i에서 처음으로 Bulk Collect 기능이 도입되었습니다. 이 기능은 PL/SQL에서 일괄 조회를 사용할 수 있고 일괄 조회는 어떤 상황에서 조회 효율을 현저히 높일 수 있습니다.현재, 우리는 이 특성에 대해 간단한 테스트와 분석을 진행한다.
1. 먼저 SQL/Plus에 기록된 100000개의 테이블을 만들고 다음 스크립트를 실행합니다.
 
drop table empl_tbl
/
create table empl_tbl(last_name varchar2(20),
first_name varchar2(10),
salary number(10))
/

begin
for i in 3000..102999 loop
insert into empl_tbl(last_name,first_name,salary) values('carl'||(i-3000),'wu'||(103000-i),i);
end loop;
end;
/
commit
/
select count(*) from empl_tbl;
/


 
2. 세 가지 방법으로 표의 한 필드에 중복되지 않는 값이 얼마나 있는지 계산한다
2.1 일반적인 Distinct를 사용한 작업
SQL>
select count(distinct last_name) "Distinct Last Name" from empl_tbl;

Distinct Last Name
------------------
            100000

Executed in 0.36 seconds


 
일반적인 방법은 0.36초가 걸려서 이 표에 중복되지 않는 100000개의 Last 를 찾아낼 수 있음을 알 수 있다name 값.
2.2 커서를 사용하여 실현
우리는 다음 문장을 실행하여 Last 를 통계한다name 필드의 반복되지 않는 값 개수:
declare
all_rows number(10);
temp_last_name empl_tbl.last_name%type;
begin
all_rows:=0;
temp_last_name:=' ';
for cur in (select last_name from empl_tbl order by last_name) loop
     
      if cur.last_name!=temp_last_name then
       all_rows:=all_rows+1;
      end if;
      temp_last_name:=cur.last_name;
     
end loop;
dbms_output.put_line('all_rows are '||all_rows);
end;

 
 
위 코드의 검은색 부분에 For Loop 커서가 사용되어 있음을 주의하십시오. 프로그램의 가독성을 높이기 위해 정의된 커서 변수를 표시하지 않았습니다.
실행 결과:allrows are 100000PL/SQL procedure successfully completedExecuted in 1.402 seconds
커서가 1.4초가 걸려야 이 테이블에 중복되지 않는 100000개의 Last 를 찾을 수 있습니다Distinct 쿼리의 3배가 넘는 시간이 소요되는 name 값
2.3 Bulk Collect 배치 질의를 사용한 작업
예제 코드는 다음과 같습니다.
declare
all_rows number(10);
--  ,    Index-by     
type last_name_tab is table of empl_tbl.last_name%type index by binary_integer;
last_name_arr last_name_tab;
--    Index-by     
temp_last_name empl_tbl.last_name%type;

begin
all_rows:=0;
temp_last_name:=' ';
--  Bulk Collect          
select last_name bulk collect into last_name_arr from empl_tbl;

for i in 1..last_name_arr.count loop
      if temp_last_name!=last_name_arr(i) then
       all_rows:=all_rows+1;
      end if;
      temp_last_name:=last_name_arr(i);
end loop;
dbms_output.put_line('all_rows are '||all_rows);
end;
 
 
위 코드에서 우리가 먼저 Index-by 테이블 데이터 형식을 정의했음을 주의하십시오 lastname_tab, 그리고 이 집합 데이터 형식의 변수last 를 정의합니다name_arr, 마지막으로 Bulk Collect 배치 질의를 사용하여 last를 채웁니다name_arr, 그것의 사용 문법에 주의하세요.
실행 결과:allrows are 100000 PL/SQL procedure successfully completed Executed in 0.28 seconds가 위에서 실행한 결과를 보면 Bulk Collect 일괄 조회는 0.28초만에 10만 개의 중복되지 않는 Last 를 찾을 수 있습니다.name 값, 소모되는 시간은 커서 조회의 5분의 1에 불과하며,Distinct의 일반적인 조회보다 빠릅니다.
3. 테스트 결과 분석은 왜 위의 결과가 나타날까요?Oracle의 SQL을 사용할 수 있습니다트레이스가 결과를 분석해 보겠습니다.SQL 명령줄에서 alter session set sql 사용trace=true 문장은 Oracle의 Trace를 열고 명령줄에서 위의 세 가지 조회를 실행하고 TKPROF 도구를 사용하여 Trace 보고서를 생성합니다.
3.1 일반 Distinct 쿼리 결과 분석*****************************************************************************************select count(distinct last name)frompltbl
call     count       cpu    elapsed       disk      query    current        rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse        1      0.00       0.00          0          0          0           0Execute      1      0.00       0.00          0          0          0           0Fetch        1      0.28       0.32        198        425          4           1------- ------ -------- ---------- ---------- ---------- ---------- ----------total        3      0.28       0.32        198        425          4           1
Misses in library cache during parse: 1Optimizer goal: CHOOSEParsing user id: 62
Rows     Row Source Operation------- ---------------------------------------------------      1 SORT GROUP BY100000   TABLE ACCESS FULL EMPL_TBL
************************************************************************************************위 조회 우선 empltbl에서 전체 테이블 스캔을 한 후에 그룹을 나누어 결과를 정렬합니다.SQL의 해석, 집행 시간은 모두 무시할 수 없다. 주요 시간은 데이터를 읽는 데 쓰인다. 왜냐하면 현재 SQL은 조회일 뿐이고 증가, 삭제 작업이 없기 때문이다.데이터 읽기 단계에서 디스크에서 198개의 Oracle 블록을 읽고 일치성 읽기 (query,consistent gets) 블록 425개를 읽어야 합니다.디스크를 물리적으로 읽는 것은 시간이 많이 걸리기 때문에, 이 검색은 실행하기에 그리 빠르지 않다.
3.2 커서 조회 효율 분석***************************************************************************************************SELECT LASTNAMEFROMEMPL_TBL ORDER BY LAST_NAME
call     count       cpu    elapsed       disk      query    current        rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse        0      0.00       0.00          0          0          0           0Execute      1      0.00       0.00          0          0          0           0Fetch   100001      0.71       0.62        198        425          4      100000------- ------ -------- ---------- ---------- ---------- ---------- ----------total   100002      0.71       0.62        198        425          4      100000
*********************************************************************************************************************************************************************************************************Distinct SQL 쿼리와 동일하지만,이 방법의 커서는 100001회 순환해야 하기 때문에 위의 SQL의 읽기는 100001회 발생하고 모두 100000줄의 데이터를 읽는다. 이것이 바로 커서를 사용하는 데 1.4초가 걸리는 이유다.Bulk Collect를 사용하면 어떻게 되는지 살펴보겠습니다.
3.3 Bulk Collect의 질의효율 분석**************************************************************************************************SELECT LASTNAMEFROMEMPL_TBL
call     count       cpu    elapsed       disk      query    current        rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse        0      0.00       0.00          0          0          0           0Execute      1      0.00       0.00          0          0          0           0Fetch        1      0.08       0.07          0        425          0      100000------- ------ -------- ---------- ---------- ---------- ---------- ----------total        2      0.08       0.07          0        425          0      100000
*********************************************************************************************************************************************************************************************************lect 문장은 필요한 데이터를 메모리에 한꺼번에 읽습니다.따라서 이 방법은 디스크에서 데이터 블록을 읽지 않았기 때문에 상술한 두 가지 방법보다 장점이 있기 때문에 실행 효율이 가장 높다.
4. 위의 테스트와 분석을 통해 Bulk Collect 일괄 조회가 어느 정도에 조회 효율을 높일 수 있음을 알 수 있다. 이는 먼저 필요한 데이터를 메모리에 읽은 다음에 통계 분석을 하면 조회 효율을 높일 수 있다.그러나 Oracle 데이터베이스의 메모리가 작고 Shared Pool Size가 Bulk Collect 일괄 조회 결과를 저장하기에 부족하다면 Bulk Collect의 집합 결과를 디스크에 저장해야 한다. 이런 상황에서 Bulk Collect 방법의 효율은 오히려 다른 두 가지 방법보다 못하기 때문에 관심 있는 독자들은 더욱 테스트할 수 있다.
또한 Bulk Collect 배치 조회 외에 FORALL 문구를 사용하여 배치 삽입, 삭제, 업데이트를 실현할 수 있어 대량의 데이터 조작을 할 때 실행 효율을 현저히 높일 수 있다.
do something like this:

   open cursor;
   loop
       fetch c bulk collect into l_c1, l_c2, ....... LIMIT 1000;
       for i in 1 .. l_c1.count
       loop
          your process....
       end loop;
       forall i in 1 .. l_c1.count
            insert into ..... values ( L_c1(i), .... );
       end loop;
       exit when c%notfound;
   end loop;

   close cursor

 

좋은 웹페이지 즐겨찾기