pero no es lo mas optimo pues consume mucha memoria y el proceso es lento...
Estas equivocado , en efecto es lo mas optimo que puede haber pero al utilizar memoria directamente hay que saberlo usar de acuerdo a las limitaciones de memoria que existan en la SGA.
Si vas a utilizar pl/sql tables lo mas conveniente es realizar bulk collect con no mas de 200.000 registros (dependiendo el tamaño de cada record), ya que si usas mas es muy probable que el motor comience a hacer swap debido al gran espacio inutilizado en memoria en un instante determinado.
Las soluciones mas óptimas para ese tipo de casos siempre son utilizando pl/sql tables, nunca se me ha presentado ningún inconveniente con cursores, como hacen los cursores? que tipo de situaciones pretenden manejar?