Reducing Oracle LOB Memory Use in PHP, or Paul's Lesson Applied to Oracle

Posted by christopher.jones on Oracle Blogs See other posts from Oracle Blogs or by christopher.jones
Published on Fri, 19 Mar 2010 16:38:12 -0800 Indexed on 2010/03/20 0:51 UTC
Read the original article Hit count: 702

Filed under: Error when finding categories...

Paul Reinheimer's PHP memory pro tip shows how re-assigning a value to a variable doesn't release the original value until the new data is ready. With large data lengths, this unnecessarily increases the peak memory usage of the application.

In Oracle you might come across this situation when dealing with LOBS. Here's an example that selects an entire LOB into PHP's memory. I see this being done all the time, not that that is an excuse to code in this style. The alternative is to remove OCI_RETURN_LOBS to return a LOB locator which can be accessed chunkwise with LOB->read().

In this memory usage example, I threw some CLOB rows into a table. Each CLOB was about 1.5M. The fetching code looked like:

$s = oci_parse ($c, 'SELECT CLOBDATA FROM CTAB');
oci_execute($s);

echo "Start Current :" . memory_get_usage() . "\n";
echo "Start Peak    : " .memory_get_peak_usage() . "\n";

while(($r = oci_fetch_array($s, OCI_RETURN_LOBS)) !== false) {
    echo "Current :" . memory_get_usage() . "\n";
    echo "Peak    : "   . memory_get_peak_usage() . "\n";
//    var_dump(substr($r['CLOBDATA'],0,10));  // do something with the LOB
//    unset($r);
}
echo "End Current :" . memory_get_usage() . "\n";
echo "End Peak    : "   . memory_get_peak_usage() . "\n";

Without "unset" in loop, $r retains the current data value while new data is fetched:

Start Current :  345300
Start Peak    :  353676
Current       : 1908092
Peak          : 2958720
Current       : 1908092
Peak          : 4520972
End Current   :  345668
End Peak      : 4520972

When I uncommented the "unset" line in the loop, PHP's peak memory usage is much lower:

Start Current :  345376
Start Peak    :  353676
Current       : 1908168
Peak          : 2958796
Current       : 1908168
Peak          : 2959108
End Current   :  345744
End Peak      : 2959108

Even if you are using LOB->read(), unsetting variables in this manner will reduce the PHP program's peak memory usage.

With LOBS in Oracle DB there is also DB memory use to consider. Using LOB->free() is worthwhile for locators. Importantly, the OCI8 1.4.1 extension (from PECL or included in PHP 5.3.2) has a LOB fix to free up Oracle's locators earlier. For long running scripts using lots of LOBS, upgrading to OCI8 1.4.1 is recommended.

© Oracle Blogs or respective owner