Using bulk collect into a collection will be faster, but talking about that amount of records, it could be also dangerous because of the per-session memory it would consume.
In this case you could use the LIMIT clause, to fetch only a smaller group of records, process them, and then fetch another group.
Here is an example:
<pre>PROCEDURE bulk_with_limit (
dept_id_in IN employees.department_id%TYPE
, limit_in IN PLS_INTEGER DEFAULT 100
WHERE department_id = dept_id_in;
TYPE employee_tt IS TABLE OF employees_cur%ROWTYPE
INDEX BY PLS_INTEGER;
BULK COLLECT INTO l_employees LIMIT limit_in;
FOR indx IN 1 .. l_employees.COUNT
process_each_employees (l_employees (indx));
EXIT WHEN employees_cur%NOTFOUND;
Coincidentally, the last issue of Oracle Magazine has a great article called “On Cursor For Loops” (from which I took this example), which covers, among other things, your specific case.
I read it on a printed version, but you can read it on-line here.