2013-10-03 1 views
3

Какой из них более совершенен.Что лучше - курсор для цикла или петли над PLSQL-коллекцией, заполненной Bulk Collect?

Version 1 использует Cursor For Loop

DECLARE 
    total_val number(6); 

    CURSOR c1 IS 
    SELECT * FROM emp 
    ; 
BEGIN 
    total_val := 0; 
    FOR emp_rec IN c1 
    LOOP 
    total_val := total_val + emp_rec.sal; 
    END LOOP; 

    DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val); 
END; 

Version 2 сначала использует Bulk Collect, чтобы получить все строки в коллекции PLSQL затем итерацию над ним.

DECLARE 
    total_val number(6); 

    CURSOR c1 IS 
    SELECT * FROM emp 
    ; 

    TYPE emp_recs_type IS TABLE OF emp%ROWTYPE; 
    emp_recs emp_recs_type; 
BEGIN 
    total_val := 0; 

    OPEN c1; 
    FETCH c1 BULK COLLECT INTO emp_recs; 
    CLOSE c1; 

    FOR l_index IN emp_recs.FIRST..emp_recs.LAST 
    LOOP 
    total_val := total_val + emp_recs(l_index).sal; 
    END LOOP; 

    DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val); 
END; 

Пожалуйста, предположим, что Cursor может возвращать множество строк, может быть в 10-ых тысяч или больше.

ответ

2

Лучший способ узнать, действительно ли создать эксперимент и попробовать его.

Конечно для вашего примера лучший код будет:

DECLARE 
    total_val number(6); 
BEGIN 
    SELECT SUM(sal) INTO total_val FROM emp; 

    DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val); 
END; 

Однако, я понимаю, что это всего лишь простой пример!

Теоретически использование BULK COLLECT должно быть лучше, но на самом деле в эти дни (конечно же, в 11G) Oracle бесшумно выгружает под покровы в любом случае в рядах по 100 рядов - см. this AskTom thread.

Если вы используете BULK COLLECT самостоятельно и может быть неопределенное количество строк, вы должны использовать предложение LIMIT, иначе вы могли бы столкнуться с проблемами памяти. Для вашего примера это будет примерно так:

DECLARE 
    total_val number(6); 

    CURSOR c1 IS 
    SELECT * FROM emp 
    ; 

    TYPE emp_recs_type IS TABLE OF emp%ROWTYPE; 
    emp_recs emp_recs_type; 
BEGIN 
    total_val := 0; 

    OPEN c1; 

    LOOP 
    FETCH c1 BULK COLLECT INTO emp_recs LIMIT 100; 

    EXIT WHEN c1.COUNT = 0; 

    FOR l_index IN emp_recs.FIRST..emp_recs.LAST 
    LOOP 
     total_val := total_val + emp_recs(l_index).sal; 
    END LOOP; 

    END LOOP; 

    DBMS_OUTPUT.PUT_LINE('TOTAL SALARIES: ' || total_val); 
    CLOSE c1; 
END; 
+1

Я думаю, что вы имели в виду 'SUM (sal)', а не 'COUNT (*)'. – AppleGrew

Смежные вопросы