PL/SQL Performance Tuning: Eliminating the Bottlenecks
Writing PL/SQL that works is easy. Writing PL/SQL that scales to process millions of rows requires a deep understanding of memory, caching, and the dreaded Context Switch.
The Context Switch Penalty
Oracle Database has two distinct engines:
- The SQL Engine: Executes queries (
SELECT,INSERT). - The PL/SQL Engine: Executes procedural code (
IF/THEN,LOOP).
When you write a PL/SQL FOR loop that executes an INSERT statement inside the loop, the PL/SQL engine must hand the data over to the SQL engine, wait for the insert, and then take back control. This handover is called a Context Switch.
If you loop 1 million times, you cause 1 million context switches. This overhead will absolutely destroy your performance. The golden rule of PL/SQL tuning is: Minimize Context Switches.
Batching with BULK COLLECT and FORALL
To eliminate context switches, we send data to the SQL engine in massive batches.
The Bad Way (Row-by-Row = Slow-by-Slow)
The Fast Way (BULK Processing)
By batching, we reduced 10,000 context switches down to just 2.
Memory Exhaustion
Do not BULK COLLECT 5 million rows at once. You will crash the server's PGA memory. Always use the LIMIT clause to fetch chunks of 5,000 to 10,000 rows at a time inside a loop.
Function Caching (RESULT_CACHE)
If you have a function that calculates a complex tax rate based on the current year, and you call it 50,000 times in a report, it executes 50,000 times. But the answer is always the same!
By adding the RESULT_CACHE clause to the function definition, Oracle executes the function once, saves the answer in shared memory, and returns the cached answer for the remaining 49,999 calls.
If the tax_rules table is updated, Oracle automatically invalidates the cache and recalculates it on the next call.
Passing by Reference (NOCOPY)
When you pass an IN OUT parameter to a procedure, Oracle makes a complete copy of the variable in memory. If you are passing a massive collection containing 10,000 records, this copying process consumes huge amounts of PGA memory and CPU.
You can tell Oracle to pass the variable by reference (just a memory pointer) using the NOCOPY compiler hint.
Common Gotchas
Important Gotchas
- !
NOCOPYis just a compiler hint. If your procedure throws an exception, standardIN OUTvariables will roll back to their original state.NOCOPYvariables will NOT roll back—they are permanently modified. Ensure you have proper exception handling. - !
Do not use
RESULT_CACHEon a function that queries a highly volatile OLTP table. The cache will constantly invalidate, and the overhead of managing the cache will actually make your function slower.
Key Takeaways
Key Takeaways
- Never use Row-by-Row processing. Use
BULK COLLECTandFORALLto eliminate context switches. - Protect your PGA memory by always using the
LIMITclause withBULK COLLECT. - Use
RESULT_CACHEfor deterministic functions to bypass expensive re-executions. - Pass massive collections to procedures using the
NOCOPYhint.


