Oracle Server Result Cache

This post is about the Oracle Server Result Cache, a free feature of Oracle Database Enterprise Edition.  It was first introduced in Oracle 11g.  There were minor changes over time and it basically works the same in Oracle 21c.  Oracle 21c added some tuning knobs including these three new init.ora parameters, two of which support caching results of queries against temporary objects:

  • RESULT_CACHE_EXECUTION_THRESHOLD
  • RESULT_CACHE_MAX_TEMP_SIZE
  • RESULT_CACHE_MAX_TEMP_RESULT

What is the Oracle Server Result Cache?

The Oracle Server Result Cache allows you to cache the results of queries and PL/SQL function calls in database server memory so that future executions of an identical query or function can immediately obtain results from the cache instead of executing and fetching data to re-formulate the results.  Without this feature, Oracle caches the SQL execution plan so it knows how to fetch the data, and it caches some or all of the data, but your query must still assemble the data blocks, sort the data, performing grouping, etc.  The Oracle Server Result Cache allows you to skip all of that work.

Result cached in memory are available to all users.  Users running the same query and want the same data can quickly pull the result set from the cache rather than actually running the query and fetching source data.  Since the result set it stored as a thing, there’s no wait time for it to be assembled.  Oracle just grabs the result set and sends it to the user.

Where is the Oracle Server Result Cache?

The Oracle Server Result Cache sits in a sub-region of the Oracle SGA's Shared Pool called the “Result Cache”.  The SGA is Oracle's entire shared memory region.  Within the SGA are numerous areas of which the Shared Pool is well known to Oracle DBAs.  Within the Shared Pool is a little known region called the Result Cache.

Within the Result Cache are two sub-areas: the Query Result Cache and the PL/SQL Function Result Cache.  These two sub-areas are auto sized by Oracle at run-time and cannot be sized by the administrator.

The Result Cache might or might not exist by default.  That varies by platform.  The cache is sized using the database initialization parameter RESULT_CACHE_MAX_SIZE.  On some platforms the default value is 0 bytes, so the cache does not exist.  On other platforms the default is a non-zero integer, so the cache does exist.  To see the current value run the following SQL statement:

SQL> show parameter result_cache_max_size;

The feature is Oracle Server Result Cache enabled by allocating memory to the cache.  The feature can be disabled by resetting the cache size to 0.  If memory has been allocated, then you should find the feature is already enabled:

SQL> select dbms_result_cache.status() from dual;

DBMS_RESULT_CACHE.STATUS()
-------------------------------------------------
ENABLED

Shared Pool memory is consumed by the Result Cache.  You should increase the Shared Pool size to avoid starving other features that use the Shared Pool.  Also, in many databases the parameter shared_pool_size is not set and defaults to 0 which means auto-managed.  This causes a problem for the Result Cache: if parameter shared_pool_size is 0 then Oracle's memory transfer fails.

Enabling the Oracle Server Result Cache

To enable the feature allocate it some memory and bounce the instance.  However, if the Shared Pool is not explicitly sized then an error can occur as discussed earlier.  Therefore, in the below example I first size the Shared Pool and then I size the Result Cache:

ALTER SYSTEM SET SHARED_POOL_SIZE=4G SCOPE=SPFILE;
ALTER SYSTEM SET RESULT_CACHE_MAX_SIZE=1G SCOPE=SPFILE;
SHUTDOWN IMMEDIATE;
STARTUP;

You can verify the feature is enabled with the following query:

SQL> select dbms_result_cache.status() from dual;

DBMS_RESULT_CACHE.STATUS()
--------------------------------------------------
ENABLED

Bouncing the instance is only required when enabling or disabling the feature.  You can resize it without a bounce as shown here:

ALTER SYSTEM SET RESULT_CACHE_MAX_SIZE=1500M;

Once parameter RESULT_CACHE_MAX_SIZE is set Oracle allocates memory as needed up to the maximum size defined by the parameter.  Oracle does not pre-allocate all of the memory specified by the init.ora parameter.  If you lower the parameter value, then Oracle starts to immediately release that memory back to the Shared Pool.

Oracle Server Result Cache Memory Notes

The Oracle Server Result Cache is part of the Shared Pool and consumes memory from the Shared Pool.  You can see this in the below output from a call to DBMS_RESULT_CACHE.MEMORY_REPORT,

R e s u l t  C a c h e  M e m o r y  R e p o r t
[Parameters]
Block Size = 1024 bytes
Maximum Cache Size = 950272 bytes (928 blocks)
Maximum Result Size = 47104 bytes (46 blocks)
[Memory]
Total Memory = 46340 bytes [0.048% of the Shared Pool]
... Fixed Memory = 10696 bytes [0.011% of the Shared Pool]
... State Object Pool = 2852 bytes [0.003% of the Shared Pool]
... Cache Memory = 32792 bytes (32 blocks) [0.034% of the Shared Pool]
....... Unused Memory = 30 blocks
....... Used Memory = 2 blocks
........... Dependencies = 1 blocks
........... Results = 1 blocks
............... SQL = 1 blocks

PL/SQL procedure successfully completed.

For Oracle 21c on most platforms the Oracle Server Result Cache is enabled by default and sized to either 1% of the Shared Pool or one-half of 1% of the SGA target.  In other words,

  • If sga_target is set, then result_cache_max_size = sga_target * 0.005.
  • If sga_target is not set, then result_cache_max_size = shared_pool_size * 0.01.

The maximum size of the Server Result Cache is always limited to 75% of the Shared Pool (i.e., shared_pool_size * 0.75).  If the user sets parameter result_cache_max_size too high, then Oracle stops allocating memory at the 75% mark.

The amount of this memory that can be used by a single result set is determined by init.ora parameter RESULT_CACHE_MAX_RESULT.  This is a percentage of the Server Result Cache memory, so the default value 5 means each result set can use up to 5% of the memory.

Configuring Oracle Server Result Cache Behavior

By default, the Server Result Cache only caches results of queries with hint /*+ RESULT_CACHE */.  There are two ways to alter the default behavior: change init.ora parameter RESULT_CACHE_MODE and alter the table's MODE attribute.

Let's first look at init.ora parameter RESULT_CACHE_MODE.  The default value is MANUAL.  It can be set differently for each PDB and for each RAC instance.  This default value MANUAL tells Oracle to only cache results of queries having the hint.  The other allowable value FORCE tells Oracle to cache all query results even if no hint was used.

The init.ora parameter has no effect on caching PL/SQL function results.  To enable caching of PL/SQL function results you must include the RESULT_CACHE clause in its definition.

Let's next look at the table attribute.  You can set the result caching mode per table using an ALTER TABLE statement and including the MODE clause like the below example.  Any table where you don't do this will inherit the mode from the init.ora parameter.  There are two allowable values: DEFAULT means result caching only occurs when init.ora parameter RESULT_CACHE_MODE=FORCE, or if that parameter is set to MANUAL and the hint /*+ RESULT_CACHE */ is specified in the query.  The below example causes Oracle to cache all query results from table foo regardless of the init.ora parameter:

ALTER TABLE FOO RESULT_CACHE (MODE FORCE);

There is also a negative query hint to block caching results.  The hint /*+ NO_RESULT_CACHE */ in your query prevents result caching even if the init.ora parameter and table attribute are both set to FORCE.

So, there are three ways to configure Oracle's behavior.  Let's wrap-up by looking at precedence:

  • The query hint takes precedence over all other settings.
  • If the query has no hint and the init.ora parameter is set to FORCE, this takes precedence over the table attribute.
  • If the query has no hint and the init.ora parameter is not FORCE, then the table attribute is used.

Using the Oracle Server Result Cache

The same query hints /*+ RESULT_CACHE */ and /*+ NO_RESULT_CACHE */ control the caching of query results and the fetching of results from the cache. 

To cache query results, include the hint /*+ RESULT_CACHE */ in your query.  Consider the following query which shows the hint:

SQL> select /*+ RESULT_CACHE */ id, fname, lname from emp order by 3,2,1;

To prevent caching of query results, include the hint /*+ NO_RESULT_CACHE */ in your query.  Consider the following query which shows the hint:

SQL> select /*+ NO_RESULT_CACHE */ id, fname, lname from emp order by 3,2,1;

To fetch a result set from the cache your query needs the same hint /*+ RESULT_CACHE */ that is used to populate the cache.  When a user runs a query with the hint, the following order of events occurs:

  • The Oracle Optimizer determines if the same query has been run previously (all queries have a unique ID tracked in the Oracle Library Cache) and if so checks the result cache for the query results. 
  • If the query has not been previously executed, or if there is no result set in the cache, then the query is run from scratch and the result set is cached. The results are then copied to the user.
  • If the query has been previously run but the result set in the cache is stale, then the query is run from scratch and the result set is cached. The results are then copied to the user.
  • If the query has been previously run and the result set in the cache are fresh, those results are returned to the user.  The query doesn't really execute or fetch data in a traditional sense.

If you don't want to retrieve result sets, then simply omit the hints from your query.  If your application is designed to always have a hint, then you can use the /*+ NO_RESULT_CACHE */ hint to prevent fetching cached results.

You can verify queries are using the Oracle Server Result Cache with EXPLAIN statements.  The below example from the Oracle docs (ref) shows the query will use result set 8fpza04gtwsfr6n595au15yj4y rather than actually fetching data from storage.

--------------------------------------------------------------
| Id | Operation          | Name                       |Rows
--------------------------------------------------------------
| 0 | SELECT STATEMENT    |                            | 11
| 1 |  RESULT CACHE       | 8fpza04gtwsfr6n595au15yj4y |
| 2 |   HASH GROUP BY     |                            | 11
| 3 |    TABLE ACCESS FULL| EMPLOYEES                  | 107
--------------------------------------------------------------

Each result set have a unique ID.  You can find these in view V$RESULT_CACHE_OBJECTS.

You can also monitor memory utilization within the Result Cache with the below command:

SET SERVEROUTPUT ON
EXECUTE DBMS_RESULT_CACHE.MEMORY_REPORT;


Comments

Popular posts from this blog

Using DBGen to Generate TPC-H Test Data

Oracle Database Smart Flash Cache (DSFC)

Understanding TPC and TPC-like Database Benchmarks