Monday, June 11, 2012

Result cache


Result cache

Result cache has been introduce in earlier version also but from Oracle 11g it has been enhanced to great level.  So let’s try to learn more about this feature. Result cache feature
does exactly what its name implies, it caches the results of queries and puts it into a slice of the shared pool.  If you have a query that is executed often and reads data that rarely changes, this feature can increase performance significantly.  When the query executes, Oracle will first look in the result cache to see if a previous result for this query is cached.  If so, it will retrieve those results instead of reading all the blocks and creating the results again.  The initial execution will run in the normal time but subsequent executions will seem to be nearly instantaneous.

Important points to understand are:

Oracle can cache the results of both SQL & PL/SQL.
Memory allocated  for the result cache is taken from the shared pool.

Let’s figure out important parameter useful to administer the result cache:

SQL>  select name,value from v$parameter where name like 'result_cache%';

NAME                           VALUE
------------------------------ -------------------------
result_cache_mode              MANUAL
result_cache_max_size          47677440
result_cache_max_result        5
result_cache_remote_expiration 0

Trying to understand these parameter:

result_cache_mode: Default value to this parameter is Manual. That means you have pass hint in the query to use the result cache feature. Other option to this parameter is force, that mean all the query will be cached but only if they fit in the cache. When using the force mode, all result will be cached. NO_RESULT_CACHE hint has to be passed if not want to cache the result.

result_cache_max_size: This the parameter which defines the size of the result cache. We need to understand, result cache is the part of shared pool and maximum size can be 75% of the shared pool.

result_cache_max_result: Specifies percentage of RESULT_CACHE_MAX_SIZE that any single query result set can occupy. (Just to prevent the big result set from throwing out all other small resultset).

result_cache_remote_expiration: It defines the number of minutes that cached the remote object will be remain valid. Value should be set to positive value if remote database is accessed for reading purpose.

I am trying to check the feature with the table whose value are very static and will not often.

10:21:02 SQL> set autotrace on
10:21:08 SQL> select count(1) from JAY.RESULTCACHE1;

  COUNT(1)
----------
  16207591


Execution Plan
----------------------------------------------------------
Plan hash value: 821388131

-----------------------------------------------------------------------------
| Id  | Operation          | Name           | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                |     1 | 16648   (2)| 00:03:20 |
|   1 |  SORT AGGREGATE    |                |     1 |            |          |
|   2 |   TABLE ACCESS FULL| RESULTCACHE1 |    16M| 16648   (2)| 00:03:20 |
-----------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
         84  recursive calls
          0  db block gets
      60637  consistent gets
      60494  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          5  sorts (memory)
          0  sorts (disk)
          1  rows processed

10:22:14 SQL>

Consistent gets and the physical read are the two important points I want to see. Now to check the feature, I have re-started the instance.

SQL> select /*+ result_cache */ count(1) from JAY.RESULTCACHE1;

  COUNT(1)
----------
  16207591


Execution Plan
----------------------------------------------------------
Plan hash value: 821388131

------------------------------------------------------------------------------------------
| Id  | Operation           | Name                       | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                            |     1 | 16648   (2)| 00:03:20 |
|   1 |  RESULT CACHE       | cbchvkkjudm1v8shgd97yfvwt4 |       |            |          |
|   2 |   SORT AGGREGATE    |                            |     1 |            |          |
|   3 |    TABLE ACCESS FULL| RESULTCACHE1             |    16M| 16648   (2)| 00:03:20 |
------------------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------

   1 - column-count=1; dependencies=(JAY.RESULTCACHE1); attributes=(single-row); name="select /*+ result_cache */ count(1) from JAY.RESULTCACHE1"

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          4  recursive calls
          0  db block gets
      60581  consistent gets
      60394  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>

For first time, we have consistent and physical reads too. Now check for the second time.

SQL> select /*+ result_cache */ count(1) from JAY.RESULTCACHE1;

  COUNT(1)
----------
  16207591


Execution Plan
----------------------------------------------------------
Plan hash value: 821388131

------------------------------------------------------------------------------------------
| Id  | Operation           | Name                       | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |                            |     1 | 16648   (2)| 00:03:20 |
|   1 |  RESULT CACHE       | cbchvkkjudm1v8shgd97yfvwt4 |       |            |          |
|   2 |   SORT AGGREGATE    |                            |     1 |            |          |
|   3 |    TABLE ACCESS FULL| RESULTCACHE1             |    16M| 16648   (2)| 00:03:20 |
------------------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------

   1 - column-count=1; dependencies=(JAY.RESULTCACHE1); attributes=(single-row); name="select /*+ result_cache */ count(1) from JAY.RESULTCACHE1"

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

Below is the overall result when I check for couple more time:

Elapsed: 00:00:14.85
consistent gets:
60581
physical reads:
60394

Elapsed: 00:00:00.06
consistent gets: 0
physical reads: 0

Elapsed: 00:00:00.04
consistent gets: 0
physical reads: 0


Many will be confuse Result cache with buffer pool and keep pool. But both are different things and that is for sure.

Result cache exist in shared pool and had nothing to do with buffer pool. Also buffer pool cache the data block and result cache, cache the result.



I check with the below to confirm that result cache exist inside the shared pool:

SQL> select * from v$sgastat where pool='shared pool' and name like 'Result%';

POOL         NAME                                BYTES
------------ ------------------------------ ----------
shared pool  Result Cache: State Objs             2896
shared pool  Result Cache                       163976
shared pool  Result Cache: Memory Mgr              200
shared pool  Result Cache: Cache Mgr               208
shared pool  Result Cache: Bloom Fltr             2048

SQL>


Oracle provided the DBMS_RESULT_CACHE package to administrator the result cache. The package can be used for:
STATUS: Display the current status of the result package.
FLUSH: to flush the cache.
Report: to check the memory report. 


SQL> select dbms_result_cache.status from dual;

STATUS
--------------------------------------------------------------------------------
ENABLED

Above confirms result cache parameter is set to non zero value.


SQL> show parameter result_cache_max_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
result_cache_max_size                big integer 46560K
SQL>


SQL> set serveroutput on size 99999
SQL> exec  DBMS_RESULT_CACHE.MEMORY_REPORT("TRUE")
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          = 1K bytes
Maximum Cache Size  = 46560K bytes (46560 blocks)
Maximum Result Size = 2328K bytes (2328 blocks)
[Memory]
Total Memory = 169328 bytes [0.004% of the Shared Pool]
... Fixed Memory = 5352 bytes [0.000% of the Shared Pool]
....... Memory Mgr = 200 bytes
....... Cache Mgr  = 208 bytes
....... Bloom Fltr = 2K bytes
....... State Objs = 2896 bytes
... Dynamic Memory = 163976 bytes [0.003% of the Shared Pool]
....... Overhead = 131208 bytes
........... Hash Table    = 64K bytes (4K buckets)
........... Chunk Ptrs    = 24K bytes (3K slots)
........... Chunk Maps    = 12K bytes
........... Miscellaneous = 28808 bytes
....... Cache Memory = 32K bytes (32 blocks)
........... Unused Memory = 30 blocks
........... Used Memory = 2 blocks
............... Dependencies = 1 blocks (1 count)
............... Results = 1 blocks
................... SQL     = 1 blocks (1 count)

PL/SQL procedure successfully completed.

SQL>




SQL> exec DBMS_RESULT_CACHE.flush;

PL/SQL procedure successfully completed.

SQL>


When to use and when not to use:

Any change in the dependent object will make entire result cached invalidated and it need to be flush out manually. But with version 11.2, Oracle manage this job automatically.

In RAC, all instance managed its own result cache. But invalidation of any of the instance cached result will be maintained across all the other instances.

Too much reading of the cache will cause latch and may also hit performance issue, so it may also need to be monitored. 




SQL> select * from v$latchname where name like 'Result Cache%'
  2  ;

    LATCH# NAME                                                                   HASH
---------- ---------------------------------------------------------------- ----------
       405 Result Cache: RC Latch                                           1054203712
       406 Result Cache: SO Latch                                            986859868
       407 Result Cache: MB Latch                                            995186388

SQL>



Also the background process that is responsible for this feature:

SQL> select description from V$BGPROCESS where name like 'RC%';

DESCRIPTION
----------------------------------------------------------------
Result Cache: Background

SQL>

We need to learn more for this feature. As always suggestions and corrections are welcome. 

2 comments:

  1. Nice to Read ....

    I did not understand - "Any change in the dependent object will make entire result cached invalidated and it need to be flush out manually. But with version 11.2, Oracle manage this job automatically. " .....

    ReplyDelete
    Replies
    1. Hi Nipanjan,

      if there is any change made in the table that is already in the cache, for 11gR1 result cache makes it invalid but not flush it out. But from 11gR2 onward, whenever their will be any change in the dependent object which is in the cache, result will be flushed automatically.

      Delete