Pipelined Table Functions: Streaming Data for Massive ETL
When transforming 50 million rows, standard functions consume all server memory and crash. Pipelined functions solve this by streaming data row-by-row directly to the consumer, drastically reducing memory overhead.
The Memory Exhaustion Problem
Imagine you need to write a PL/SQL function that parses a complex 5GB text file, validates the data, and returns it to a SQL INSERT statement.
If you use a standard PL/SQL function that returns a Collection (like a nested table), the function must parse the entire 5GB file, load all 10 million rows into a collection variable in the PGA (Program Global Area) memory, and only then return it to the SQL engine.
This will almost certainly result in an ORA-04030: out of process memory crash.
Pipelined Functions fix this. Instead of returning the entire collection at once, a pipelined function yields (pipes) one row at a time. The SQL engine consumes that row immediately and discards it from memory, waiting for the next row. It is a true data stream.
Step 1: Creating SQL Object Types
Because pipelined functions return data that SQL can query, the return type must be known to the SQL engine (you cannot use PL/SQL-only types defined in a package spec).
First, create an Object Type to represent a single row, and then a Nested Table Type to represent the collection.
Step 2: Writing the Pipelined Function
To make a function pipelined, you add the PIPELINED keyword. Inside the loop, instead of adding data to a collection variable, you use the PIPE ROW() command.
Finally, a pipelined function ends with a naked RETURN; statement (you do not return a variable).
Step 3: Querying with TABLE()
You cannot call a pipelined function like a normal PL/SQL function. You must query it inside a SELECT statement, wrapped in the TABLE() operator.
Because it streams, the first few rows will appear in your SQL client instantly, even if you asked for 500,000 rows. The memory overhead remains near zero throughout the entire execution.
Common Gotchas
Important Gotchas
- !
By default, you cannot execute
INSERT,UPDATE, orDELETEstatements inside a pipelined function (because it's being called from aSELECTquery, which must be read-only). If you absolutely must log data or modify tables inside the stream, you must usePRAGMA AUTONOMOUS_TRANSACTION. - !
If you want your pipelined function to be executed by multiple parallel worker threads, you must explicitly enable it using
PARALLEL_ENABLEin the function signature. You must also define how the input cursor data is partitioned among the workers.
Key Takeaways
Key Takeaways
- Use Pipelined Functions for massive ETL transformations to prevent memory exhaustion.
- Declare SQL-level Object Types and Nested Table Types for the return format.
- Use
PIPE ROW()to stream data, and end the function withRETURN;. - Use the
TABLE()operator in SQL to query the resulting stream.


