2017-01-19 2 views
0

У меня есть код в моей процедуре pl/sql, который пытается собрать 17 миллионов строк, и с ошибкой ORA-04030: из памяти процесса при попытке выделить 16328 байт (KOH-kghu вызовов, pmuccst: ADT/запись)Проблема с BULK COLLECT из миллиона строк - из памяти процесса

TYPE rc_test IS RECORD(
    ROWID VARCHAR2(200), 
    contact_id VARCHAR2(200), 
    last_name VARCHAR2(200), 
    first_name VARCHAR2(200), 
    phone VARCHAR2(200), 
    email VARCHAR2(200), 
    birth_day date, 
    address_id VARCHAR2(200), 
    seq NUMBER, 
    NEWID NUMBER); 

TYPE rctype 
    IS TABLE OF RC_TEST; 

rcrecords RCTYPE; 

BEGIN 

SELECT ROWID, 
     contact_id, 
     last_name, 
     first_name, 
     phone, 
     email, 
     birth_day, 
     address_id, 
     seq, 
     NEWID 
bulk collect INTO rcrecords 
FROM HR.TMP_TBL_SEQ a 
order by last_name, first_name, seq; 

FOR i IN 1..rcrecords.count LOOP 

- < < >> END LOOP;

Он отлично работает с образцами данных сотен или тысяч строк, но не работает с миллионами строк.

Я прочитал об устранении этой ошибки, но большинство из них вращается вокруг того, чтобы сделать это через DBA, который будет выполнять некоторые настройки или посоветует нам увеличить объем оперативной памяти, который может решить проблему, но из-за определенных ограничений на первом месте, я действительно хочу для изменения логики самого кода.

Есть ли лучший способ улучшить логику вышеуказанного типа кода, чтобы избавиться от ошибки из памяти?

Вместо записи таблицы, используемой в моем коде, кто-нибудь может предоставить мне альтернативный код?

Большое спасибо.

ответ

0

Вы можете использовать BULK COLLECT с LIMIT (http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28plsql-095155.html). В вашем случае это будет выглядеть так:

CURSOR cur1 IS 
    SELECT ROWID, contact_id, last_name, first_name, 
    phone, email, birth_day, address_id, seq, 
    NEWID FROM HR.TMP_TBL_SEQ a order by last_name, first_name, seq; 
TYPE T_TEST IS TABLE OF cur1 %ROWTYPE INDEX BY PLS_INTEGER;; 
test_data T_TEST; 
BEGIN 
OPEN cur1; 
LOOP 
    FETCH cur1 
     BULK COLLECT INTO test_data LIMIT 10000; 

    FOR indx IN 1 .. test_data.COUNT 
    LOOP 
     NULL; 
     --- process data 
    END LOOP; 

    EXIT WHEN test_data.COUNT < 10000; 
END LOOP; 
CLOSE cur1; 
0

избежать такого рода «неограниченного» использования BULK COLLECT с помощью предложения LIMIT. Переведите инструкцию SELECT в явное объявление курсора, а затем используйте простой цикл для извлечения многих, но не всех строк из таблицы, при каждом выполнении тела цикла с использованием необязательного предложения LIMIT.

Для получения примеров и объяснений см этого оракула технически вопрос, см http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28plsql-095155.html

0

Заменить BULK COLLECT с курсором для цикла:

begin 
    for rcrecords in 
    (
     SELECT ROWID, 
       contact_id, 
       last_name, 
       first_name, 
       phone, 
       email, 
       birth_day, 
       address_id, 
       seq, 
       NEWID 
     bulk collect INTO rcrecords 
     FROM HR.TMP_TBL_SEQ a 
     order by last_name, first_name, seq 
    ) loop 
     --Process data. 
     null; 
    end loop; 
end; 
/

Oracle будет автоматически заботиться о насыпи сбора, ограничение, и объявление типов данных.