Oracle 之 bulk collect 的用法

style="WIDTH: 345px; HEIGHT: 285px" align="left" marginwidth="0" marginheight="0" src="http://www.ymfund.com/web/ad.html" frameborder="0" width="468" scrolling="no" height="60">

通過bulk collect減少loop處理的開銷

採用bulk collect可以將查詢結果一次性地加載到collections中。

而不是通過cursor一條一條地處理。

可以在select into,fetch into,returning into語句使用bulk collect。

注意在使用bulk collect時,所有的into變量都必須是collections.

舉幾個簡單的例子:

--在select into語句中使用bulk collect

DECLARE
   TYPE sallist 
IS TABLE OF emp.sal%TYPE;

   sals   sallist;
BEGIN
-- Limit the number of rows to 100.
   SELECT sal
   
BULK COLLECT INTO sals
     
FROM emp
    
WHERE ROWNUM <= 100;
-- Retrieve 10% (approximately) of the rows in the table.
   SELECT sal BULK COLLECT INTO sals FROM emp SAMPLE 10;
END;

--在fetch into中使用bulk collect

DECLARE
   TYPE deptrectab 
IS TABLE OF dept%ROWTYPE;

   dept_recs   deptrectab;

   
CURSOR c1
   
IS
      
SELECT deptno, dname, loc
        
FROM dept
       
WHERE deptno > 10;
BEGIN
   
OPEN c1;

   
FETCH c1
   
BULK COLLECT INTO dept_recs;
END;

在returning into中使用bulk collect

CREATE TABLE emp2 AS SELECT * FROM employees;

DECLARE
   TYPE numlist 
IS TABLE OF employees.employee_id%TYPE;

   enums   numlist;

   TYPE namelist 
IS TABLE OF employees.last_name%TYPE;

   names   namelist;
BEGIN
   
DELETE FROM emp2
         
WHERE department_id = 30
     RETURNING       employee_id, last_name
   
BULK COLLECT INTO enums, names;

   DBMS_OUTPUT.put_line (
'Deleted ' || SQL%ROWCOUNT || ' rows:');

   
FOR i IN enums.FIRST .. enums.LAST
   LOOP
      DBMS_OUTPUT.put_line (
'Employee #' || enums (i) || '' || names (i));
   
END LOOP;
END;
/

DROP TABLE emp2;

這裏有一個很好的例子

 

CREATE OR REPLACE PACKAGE comp_analysis
IS
   
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
      
RETURN BOOLEAN;
END comp_analysis;
/    
CREATE OR REPLACE PACKAGE BODY comp_analysis
IS
   
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
      
RETURN BOOLEAN
   
IS
   
BEGIN
      
RETURN MOD (id_in, 2= 0;
   
END;
END comp_analysis;
/    
CREATE OR REPLACE PROCEDURE give_raises_in_department1 (
   dept_in 
IN lots_of_employees.department_id%TYPE
 , newsal 
IN lots_of_employees.salary%TYPE
)
IS
   
CURSOR emp_cur
   
IS
      
SELECT employee_id, salary, hire_date
        
FROM lots_of_employees
       
WHERE (department_id = dept_in OR dept_IN IS NULL);

   emp_rec emp_cur
%ROWTYPE;
BEGIN
   
OPEN emp_cur;

   LOOP
      
FETCH emp_cur
       
INTO emp_rec;

      
EXIT WHEN emp_cur%NOTFOUND;

      
IF comp_analysis.is_eligible (emp_rec.employee_id)
      
THEN
         
UPDATE lots_of_employees
            
SET salary = newsal
          
WHERE employee_id = emp_rec.employee_id;
      
ELSE
         
INSERT INTO employee_history
                     (employee_id, salary
                    , hire_date, activity
                     )
              
VALUES (emp_rec.employee_id, emp_rec.salary
                    , emp_rec.hire_date, 
'RAISE DENIED'
                     );
      
END IF;
   
END LOOP;
END give_raises_in_department1;
/
SHO ERR

REM
REM Pre
-10g create multiple copies of collection
REM 
for different purposes.
REM

CREATE OR REPLACE PROCEDURE give_raises_in_department2 (
   dept_in 
IN lots_of_employees.department_id%TYPE
 , newsal 
IN lots_of_employees.salary%TYPE
)
IS
   TYPE employee_aat 
IS TABLE OF lots_of_employees.employee_id%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE salary_aat 
IS TABLE OF lots_of_employees.salary%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE hire_date_aat 
IS TABLE OF lots_of_employees.hire_date%TYPE
      
INDEX BY PLS_INTEGER;
      
   employee_ids employee_aat;
   salaries salary_aat;
   hire_dates hire_date_aat;

   approved_employee_ids employee_aat;
   
   denied_employee_ids employee_aat;
   denied_salaries salary_aat;
   denied_hire_dates hire_date_aat;

   
PROCEDURE retrieve_employee_info
   
IS
   
BEGIN
      
SELECT employee_id, salary, hire_date
      
BULK COLLECT INTO employee_ids, salaries, hire_dates
        
FROM lots_of_employees
       
WHERE (department_id = dept_in OR dept_IN IS NULL);
   
END;

   
PROCEDURE partition_by_eligibility
   
IS
   
BEGIN
      
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
      LOOP
         
IF comp_analysis.is_eligible (employees (indx))
         
THEN
            approved_employee_ids (indx) :
= employees (indx);
         
ELSE
            denied_employee_ids (indx) :
= employees (indx);
            denied_salaries (indx) :
= salaries (indx);
            denied_hire_dates (indx) :
= hire_dates (indx);
         
END IF;
      
END LOOP;
   
END;

   
PROCEDURE add_to_history
   
IS
   
BEGIN
      FORALL indx 
IN denied_employee_ids.FIRST .. denied_employee_ids.LAST
         
INSERT INTO employee_history
                     (employee_id
                    , salary
                    , hire_date, activity
                     )
              
VALUES (denied_employee_ids (indx)
                    , denied_salaries (indx)
                    , denied_hire_dates (indx), 
'RAISE DENIED'
                     );
   
END;

   
PROCEDURE give_the_raise
   
IS
   
BEGIN
      FORALL indx 
IN approved_employee_ids.FIRST .. approved_employee_ids.LAST
         
UPDATE lots_of_employees
            
SET salary = newsal
          
WHERE employee_id = approved_employee_ids (indx);
   
END;
BEGIN
   retrieve_employee_info;
   partition_by_eligibility;
   add_to_history;
   give_the_raise;
END give_raises_in_department2;
/
SHO ERR

REM
REM 10g usage 
of INDICES OF
REM

CREATE OR REPLACE PROCEDURE give_raises_in_department3 (
   dept_in 
IN lots_of_employees.department_id%TYPE
 , newsal 
IN lots_of_employees.salary%TYPE
)
IS
   TYPE employee_aat 
IS TABLE OF lots_of_employees.employee_id%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE salary_aat 
IS TABLE OF lots_of_employees.salary%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE hire_date_aat 
IS TABLE OF lots_of_employees.hire_date%TYPE
      
INDEX BY PLS_INTEGER;
      
   employee_ids employee_aat;
   salaries salary_aat;
   hire_dates hire_date_aat;

   TYPE guide_aat 
IS TABLE OF BOOLEAN
      
INDEX BY PLS_INTEGER;

   approved_list guide_aat;
   denied_list guide_aat;

   
PROCEDURE retrieve_employee_info
   
IS
   
BEGIN
      
SELECT employee_id, salary, hire_date
      
BULK COLLECT INTO employee_ids, salaries, hire_dates
        
FROM lots_of_employees
       
WHERE (department_id = dept_in OR dept_IN IS NULL);
   
END;

   
PROCEDURE partition_by_eligibility
   
IS
   
BEGIN
      
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
      LOOP
         
IF comp_analysis.is_eligible (employees(indx))
         
THEN
            approved_list (indx) :
= TRUE;
         
ELSE
            denied_list (indx) :
= TRUE;
         
END IF;
      
END LOOP;
   
END;

   
PROCEDURE add_to_history
   
IS
   
BEGIN
      FORALL indx 
IN INDICES OF denied_list
         
INSERT INTO employee_history
                     (employee_id
                    , salary
                    , hire_date, activity
                     )
              
VALUES (employees (indx)
                    , salaries (indx)
                    , hire_dates (indx)
                    , 
'RAISE DENIED'
                     );
   
END;

   
PROCEDURE give_the_raise
   
IS
   
BEGIN
      FORALL indx 
IN INDICES OF approved_list
         
UPDATE lots_of_employees
            
SET salary = newsal
              , hire_date 
= hire_dates(indx)
          
WHERE employee_id = employees(indx);
   
END;
BEGIN
   retrieve_employee_info;
   partition_by_eligibility;
   add_to_history;
   give_the_raise;
END give_raises_in_department3;
/
SHO ERR

REM
REM 10g usage 
of VALUES OF
REM

CREATE OR REPLACE PROCEDURE give_raises_in_department4 (
   dept_in 
IN lots_of_employees.department_id%TYPE
 , newsal 
IN lots_of_employees.salary%TYPE
)
IS
   TYPE employee_aat 
IS TABLE OF lots_of_employees.employee_id%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE salary_aat 
IS TABLE OF lots_of_employees.salary%TYPE
      
INDEX BY PLS_INTEGER;
   TYPE hire_date_aat 
IS TABLE OF lots_of_employees.hire_date%TYPE
      
INDEX BY PLS_INTEGER;
      
   employee_ids employee_aat;
   salaries salary_aat;
   hire_dates hire_date_aat;

   TYPE guide_aat 
IS TABLE OF PLS_INTEGER
      
INDEX BY PLS_INTEGER;

   approved_list guide_aat;
   denied_list guide_aat;

   
PROCEDURE retrieve_employee_info
   
IS
   
BEGIN
      
SELECT employee_id, salary, hire_date
      
BULK COLLECT INTO employee_ids, salaries, hire_dates
        
FROM lots_of_employees
       
WHERE (department_id = dept_in OR dept_IN IS NULL);
   
END;

   
PROCEDURE partition_by_eligibility
   
IS
   
BEGIN
      
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
      LOOP
         
IF comp_analysis.is_eligible (employees(indx))
         
THEN
            approved_list (indx) :
= indx;
         
ELSE
            denied_list (indx) :
= indx;
         
END IF;
      
END LOOP;
   
END;

   
PROCEDURE add_to_history
   
IS
   
BEGIN
      FORALL indx 
IN VALUES OF denied_list
         
INSERT INTO employee_history
                     (employee_id
                    , salary
                    , hire_date, activity
                     )
              
VALUES (employees (indx)
                    , salaries (indx)
                    , hire_dates (indx)
                    , 
'RAISE DENIED'
                     );
   
END;

   
PROCEDURE give_the_raise
   
IS
   
BEGIN
      FORALL indx 
IN VALUES OF approved_list
         
UPDATE lots_of_employees
            
SET salary = newsal
              , hire_date 
= hire_dates(indx)
          
WHERE employee_id = employees(indx);
   
END;
BEGIN
   retrieve_employee_info;
   partition_by_eligibility;
   add_to_history;
   give_the_raise;
END give_raises_in_department4;
/
SHO ERR

SET TIMING ON

BEGIN
   give_raises_in_department1 (
NULL1000);
END;
/
BEGIN
   give_raises_in_department2 (
NULL1000);
END;
/
BEGIN
   give_raises_in_department3 (
NULL1000);
END;
/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章