8.12 PL/SQL Function Result Cache
When a PL/SQL function has the RESULT_CACHE option, its results are cached in the shared global area (SGA) so sessions connected to the same instance can reuse these results when available.
Oracle Database automatically detects all data sources (tables and views) that are queried while a result-cached function is running. If changes to any of these data sources are committed, the cached result becomes invalid across all instances. The best candidates for result-caching are functions that are invoked frequently but depend on information that changes infrequently or never.
Topics
8.12.1 Enabling Result-Caching for a Function
To make a function result-cached, include the RESULT_CACHE clause in the function declaration and definition. For syntax details, see "Function Declaration and Definition".
Note:
For more information about configuring and managing the database server result cache, see Oracle Database Reference and Oracle Database Performance Tuning Guide.
In Example 8-37, the package department_pkg declares and then defines a result-cached function, get_dept_info, which returns a record of information about a given department. The function depends on the database tables DEPARTMENTS and EMPLOYEES.
You invoke the function get_dept_info as you invoke any function. For example, this invocation returns a record of information about department number 10:
department_pkg.get_dept_info(10);
This invocation returns only the name of department number 10:
department_pkg.get_dept_info(10).dept_name;
If the result for get_dept_info(10) is in the result cache, the result is returned from the cache; otherwise, the result is computed and added to the cache. Because get_dept_info depends on the DEPARTMENTS and EMPLOYEES tables, any committed change to DEPARTMENTS or EMPLOYEES invalidates all cached results for get_dept_info, relieving you of programming cache invalidation logic everywhere that DEPARTMENTS or EMPLOYEES might change.
Example 8-37 Declaring and Defining Result-Cached Function
CREATE OR REPLACE PACKAGE department_pkg AUTHID DEFINER IS
TYPE dept_info_record IS RECORD (
dept_name departments.department_name%TYPE,
mgr_name employees.last_name%TYPE,
dept_size PLS_INTEGER
);
-- Function declaration
FUNCTION get_dept_info (dept_id NUMBER)
RETURN dept_info_record
RESULT_CACHE;
END department_pkg;
/
CREATE OR REPLACE PACKAGE BODY department_pkg IS
-- Function definition
FUNCTION get_dept_info (dept_id NUMBER)
RETURN dept_info_record
RESULT_CACHE
IS
rec dept_info_record;
BEGIN
SELECT department_name INTO rec.dept_name
FROM departments
WHERE department_id = dept_id;
SELECT e.last_name INTO rec.mgr_name
FROM departments d, employees e
WHERE d.department_id = dept_id
AND d.manager_id = e.employee_id;
SELECT COUNT(*) INTO rec.dept_size
FROM EMPLOYEES
WHERE department_id = dept_id;
RETURN rec;
END get_dept_info;
END department_pkg;
/
8.12.2 Developing Applications with Result-Cached Functions
When developing an application that uses a result-cached function, make no assumptions about the number of times the body of the function will run for a given set of parameter values.
Some situations in which the body of a result-cached function runs are:
-
The first time a session on this database instance invokes the function with these parameter values
-
When the cached result for these parameter values is invalid
When a change to any data source on which the function depends is committed, the cached result becomes invalid.
-
When the cached results for these parameter values have aged out
If the system needs memory, it might discard the oldest cached values.
-
When the function bypasses the cache (see "Result Cache Bypass")
8.12.3 Requirements for Result-Cached Functions
A result-cached PL/SQL function is safe if it always produces the same output for any input that it would produce were it not marked with RESULT_CACHE. This safety is only guaranteed if these conditions are met:
-
When the function is executed, it has no side effects.
For information about side effects, see "Subprogram Side Effects".
-
All tables that the function accesses are ordinary, non-
SYS-owned permanent tables in the same database as the function. -
The function’s result must be determined only by the vector of input actuals together with the committed content, at the current
SCN, of the tables that it references.
It is recommended that a result-cached function also meet these criteria:
-
It does not depend on session-specific settings.
For more information, see "Making Result-Cached Functions Handle Session-Specific Settings".
-
It does not depend on session-specific application contexts.
For more information, see "Making Result-Cached Functions Handle Session-Specific Application Contexts".
For more information, see Oracle Database Performance Tuning Guide.
8.12.4 Examples of Result-Cached Functions
The best candidates for result-caching are functions that are invoked frequently but depend on information that changes infrequently (as might be the case in the first example). Result-caching avoids redundant computations in recursive functions.
Examples:
8.12.4.1 Result-Cached Application Configuration Parameters
Consider an application that has configuration parameters that can be set at either the global level, the application level, or the role level. The application stores the configuration information in these tables:
-- Global Configuration Settings DROP TABLE global_config_params; CREATE TABLE global_config_params (name VARCHAR2(20), -- parameter NAME val VARCHAR2(20), -- parameter VALUE PRIMARY KEY (name) ); -- Application-Level Configuration Settings CREATE TABLE app_level_config_params (app_id VARCHAR2(20), -- application ID name VARCHAR2(20), -- parameter NAME val VARCHAR2(20), -- parameter VALUE PRIMARY KEY (app_id, name) ); -- Role-Level Configuration Settings CREATE TABLE role_level_config_params (role_id VARCHAR2(20), -- application (role) ID name VARCHAR2(20), -- parameter NAME val VARCHAR2(20), -- parameter VALUE PRIMARY KEY (role_id, name) );
For each configuration parameter, the role-level setting overrides the application-level setting, which overrides the global setting. To determine which setting applies to a parameter, the application defines the PL/SQL function get_value. Given a parameter name, application ID, and role ID, get_value returns the setting that applies to the parameter.
The function get_value is a good candidate for result-caching if it is invoked frequently and if the configuration information changes infrequently.
Example 8-38 shows a possible definition for get_value. Suppose that for one set of parameter values, the global setting determines the result of get_value. While get_value is running, the database detects that three tables are queried—role_level_config_params, app_level_config_params, and global_config_params. If a change to any of these three tables is committed, the cached result for this set of parameter values is invalidated and must be recomputed.
Now suppose that, for a second set of parameter values, the role-level setting determines the result of get_value. While get_value is running, the database detects that only the role_level_config_params table is queried. If a change to role_level_config_params is committed, the cached result for the second set of parameter values is invalidated; however, committed changes to app_level_config_params or global_config_params do not affect the cached result.
Example 8-38 Result-Cached Function Returns Configuration Parameter Setting
CREATE OR REPLACE FUNCTION get_value (p_param VARCHAR2, p_app_id NUMBER, p_role_id NUMBER ) RETURN VARCHAR2 RESULT_CACHE AUTHID DEFINER IS answer VARCHAR2(20); BEGIN -- Is parameter set at role level? BEGIN SELECT val INTO answer FROM role_level_config_params WHERE role_id = p_role_id AND name = p_param; RETURN answer; -- Found EXCEPTION WHEN no_data_found THEN NULL; -- Fall through to following code END; -- Is parameter set at application level? BEGIN SELECT val INTO answer FROM app_level_config_params WHERE app_id = p_app_id AND name = p_param; RETURN answer; -- Found EXCEPTION WHEN no_data_found THEN NULL; -- Fall through to following code END; -- Is parameter set at global level? SELECT val INTO answer FROM global_config_params WHERE name = p_param; RETURN answer; END;
8.12.4.2 Result-Cached Recursive Function
A recursive function for finding the nth term of a Fibonacci series that mirrors the mathematical definition of the series might do many redundant computations. For example, to evaluate fibonacci(7), the function must compute fibonacci(6) and fibonacci(5). To compute fibonacci(6), the function must compute fibonacci(5) and fibonacci(4). Therefore, fibonacci(5) and several other terms are computed redundantly. Result-caching avoids these redundant computations.
Note:
The maximum number of recursive invocations cached is 128.
CREATE OR REPLACE FUNCTION fibonacci (n NUMBER)
RETURN NUMBER
RESULT_CACHE
AUTHID DEFINER
IS
BEGIN
IF (n =0) OR (n =1) THEN
RETURN 1;
ELSE
RETURN fibonacci(n - 1) + fibonacci(n - 2);
END IF;
END;
/8.12.5 Advanced Result-Cached Function Topics
Topics
8.12.5.1 Rules for a Cache Hit
Each time a result-cached function is invoked with different parameter values, those parameters and their result are stored in the cache. Subsequently, when the same function is invoked with the same parameter values (that is, when there is a cache hit), the result is retrieved from the cache, instead of being recomputed.
The rules for parameter comparison for a cache hit differ from the rules for the PL/SQL "equal to" (=) operator, as follows:
| Category | Cache Hit Rules | "Equal To" Operator Rules |
|---|---|---|
|
NULL comparison |
|
|
|
Non-null scalar comparison |
Non-null scalars are the same if and only if their values are identical; that is, if and only if their values have identical bit patterns on the given platform. For example, |
Non-null scalars can be equal even if their values do not have identical bit patterns on the given platform; for example, |
8.12.5.2 Result Cache Bypass
In some situations, the cache is bypassed. When the cache is bypassed:
-
The function computes the result instead of retrieving it from the cache.
-
The result that the function computes is not added to the cache.
Some examples of situations in which the cache is bypassed are:
-
The cache is unavailable to all sessions.
For example, the database administrator has disabled the use of the result cache during application patching (as in "Hot-Patching PL/SQL Units on Which Result-Cached Functions Depend").
-
A session is performing a DML statement on a table or view on which a result-cached function depends.
The session bypasses the result cache for that function until the DML statement is completed—either committed or rolled back. If the statement is rolled back, the session resumes using the cache for that function.
Cache bypass ensures that:
-
The user of each session sees his or her own uncommitted changes.
-
The PL/SQL function result cache has only committed changes that are visible to all sessions, so that uncommitted changes in one session are not visible to other sessions.
-
8.12.5.3 Making Result-Cached Functions Handle Session-Specific Settings
If a function depends on settings that might vary from session to session (such as NLS_DATE_FORMAT and TIME ZONE), make the function result-cached only if you can modify it to handle the various settings.
The function, get_hire_date, in Example 8–39 uses the TO_CHAR function to convert a DATE item to a VARCHAR item. The function get_hire_date does not specify a format mask, so the format mask defaults to the one that NLS_DATE_FORMAT specifies. If sessions that invoke get_hire_date have different NLS_DATE_FORMAT settings, cached results can have different formats. If a cached result computed by one session ages out, and another session recomputes it, the format might vary even for the same parameter value. If a session gets a cached result whose format differs from its own format, that result is probably incorrect.
Some possible solutions to this problem are:
-
Change the return type of
get_hire_datetoDATEand have each session invoke theTO_CHARfunction. -
If a common format is acceptable to all sessions, specify a format mask, removing the dependency on
NLS_DATE_FORMAT. For example:TO_CHAR(date_hired, 'mm/dd/yy');
-
Add a format mask parameter to
get_hire_date. For example:CREATE OR REPLACE FUNCTION get_hire_date (emp_id NUMBER, fmt VARCHAR) RETURN VARCHAR RESULT_CACHE AUTHID DEFINER IS date_hired DATE; BEGIN SELECT hire_date INTO date_hired FROM HR.EMPLOYEES WHERE EMPLOYEE_ID = emp_id; RETURN TO_CHAR(date_hired, fmt); END; /
Example 8-39 Result-Cached Function Handles Session-Specific Settings
CREATE OR REPLACE FUNCTION get_hire_date (emp_id NUMBER) RETURN VARCHAR RESULT_CACHE AUTHID DEFINER IS date_hired DATE; BEGIN SELECT hire_date INTO date_hired FROM HR.EMPLOYEES WHERE EMPLOYEE_ID = emp_id; RETURN TO_CHAR(date_hired); END; /
8.12.5.4 Making Result-Cached Functions Handle Session-Specific Application Contexts
An application context, which can be either global or session-specific, is a set of attributes and their values. A PL/SQL function depends on session-specific application contexts if it does one or more of the following:
-
Directly invokes the SQL function
SYS_CONTEXT, which returns the value of a specified attribute in a specified context -
Indirectly invokes
SYS_CONTEXTby using Virtual Private Database (VPD) mechanisms for fine-grained security(For information about VPD, see Oracle Database Security Guide.)
The PL/SQL function result-caching feature does not automatically handle dependence on session-specific application contexts. If you must cache the results of a function that depends on session-specific application contexts, you must pass the application context to the function as a parameter. You can give the parameter a default value, so that not every user must specify it.
In Example 8-40, assume that a table, config_tab, has a VPD policy that translates this query:
SELECT value FROM config_tab WHERE name = param_name;
To this query:
SELECT value FROM config_tab
WHERE name = param_name
AND app_id = SYS_CONTEXT('Config', 'App_ID');Example 8-40 Result-Cached Function Handles Session-Specific Application Context
CREATE OR REPLACE FUNCTION get_param_value (
param_name VARCHAR,
appctx VARCHAR DEFAULT SYS_CONTEXT('Config', 'App_ID')
) RETURN VARCHAR
RESULT_CACHE
AUTHID DEFINER
IS
rec VARCHAR(2000);
BEGIN
SELECT val INTO rec
FROM config_tab
WHERE name = param_name;
RETURN rec;
END;
/8.12.5.5 Choosing Result-Caching Granularity
PL/SQL provides the function result cache, but you choose the caching granularity. To understand the concept of granularity, consider the Product_Descriptions table in the Order Entry (OE) sample schema:
NAME NULL? TYPE ---------------------- -------- --------------- PRODUCT_ID NOT NULL NUMBER(6) LANGUAGE_ID NOT NULL VARCHAR2(3) TRANSLATED_NAME NOT NULL NVARCHAR2(50) TRANSLATED_DESCRIPTION NOT NULL NVARCHAR2(2000)
The table has the name and description of each product in several languages. The unique key for each row is PRODUCT_ID,LANGUAGE_ID.
Suppose that you must define a function that takes a PRODUCT_ID and a LANGUAGE_ID and returns the associated TRANSLATED_NAME. You also want to cache the translated names. Some of the granularity choices for caching the names are:
-
One name at a time (finer granularity)
-
One language at a time (coarser granularity)
Table 8-4 Finer and Coarser Caching Granularity
| Granularity | Benefits |
|---|---|
|
Finer |
Each function result corresponds to one logical result. Stores only data that is needed at least once. Each data item ages out individually. Does not allow bulk loading optimizations. |
|
Coarser |
Each function result contains many logical subresults. Might store data that is never used. One aged-out data item ages out the whole set. Allows bulk loading optimizations. |
In Example 8-41 and Example 8-42, the function productName takes a PRODUCT_ID and a LANGUAGE_ID and returns the associated TRANSLATED_NAME. Each version of productName caches translated names, but at a different granularity.
In Example 8-41, get_product_name_1 is a result-cached function. Whenever get_product_name_1 is invoked with a different PRODUCT_ID and LANGUAGE_ID, it caches the associated TRANSLATED_NAME. Each invocation of get_product_name_1 adds at most one TRANSLATED_NAME to the cache.
In Example 8-42, get_product_name_2 defines a result-cached function, all_product_names. Whenever get_product_name_2 invokes all_product_names with a different LANGUAGE_ID, all_product_names caches every TRANSLATED_NAME associated with that LANGUAGE_ID. Each invocation of all_product_names adds every TRANSLATED_NAME of at most one LANGUAGE_ID to the cache.
Example 8-41 Caching One Name at a Time (Finer Granularity)
CREATE OR REPLACE FUNCTION get_product_name_1 (
prod_id NUMBER,
lang_id VARCHAR2
)
RETURN NVARCHAR2
RESULT_CACHE
AUTHID DEFINER
IS
result_ VARCHAR2(50);
BEGIN
SELECT translated_name INTO result_
FROM OE.Product_Descriptions
WHERE PRODUCT_ID = prod_id
AND LANGUAGE_ID = lang_id;
RETURN result_;
END;
/
Example 8-42 Caching Translated Names One Language at a Time (Coarser Granularity)
CREATE OR REPLACE FUNCTION get_product_name_2 (
prod_id NUMBER,
lang_id VARCHAR2
)
RETURN NVARCHAR2
AUTHID DEFINER
IS
TYPE product_names IS TABLE OF NVARCHAR2(50) INDEX BY PLS_INTEGER;
FUNCTION all_product_names (lang_id VARCHAR2)
RETURN product_names
RESULT_CACHE
IS
all_names product_names;
BEGIN
FOR c IN (SELECT * FROM OE.Product_Descriptions
WHERE LANGUAGE_ID = lang_id) LOOP
all_names(c.PRODUCT_ID) := c.TRANSLATED_NAME;
END LOOP;
RETURN all_names;
END;
BEGIN
RETURN all_product_names(lang_id)(prod_id);
END;
/8.12.5.6 Result Caches in Oracle RAC Environment
Cached results are stored in the system global area (SGA). In an Oracle RAC environment, each database instance manages its own local function result cache. However, the contents of the local result cache are accessible to sessions attached to other Oracle RAC instances. If a required result is missing from the result cache of the local instance, the result might be retrieved from the local cache of another instance, instead of being locally computed.
The access pattern and work load of an instance determine the set of results in its local cache; therefore, the local caches of different instances can have different sets of results.
Although each database instance might have its own set of cached results, the mechanisms for handling invalid results are Oracle RAC environment-wide. If results were invalidated only in the local instance's result cache, other instances might use invalid results. For example, consider a result cache of item prices that are computed from data in database tables. If any of these database tables is updated in a way that affects the price of an item, the cached price of that item must be invalidated in every database instance in the Oracle RAC environment.
8.12.5.7 Result Cache Management
The PL/SQL function result cache shares its administrative and manageability infrastructure with the Result Cache.
The database administrator manages the server result cache by specifying the RESULT_CACHE_MAX_SIZE , RESULT_CACHE_MAX_RESULT and RESULT_CACHE_REMOTE_EXPIRATION initialization parameters.
The DBMS_RESULT_CACHE package provides an interface to allow the DBA to administer that part of the shared pool that is used by the SQL result cache and the PL/SQL function result cache.
Dynamic performance views provide information to monitor the server and client result caches.
See Also:
-
Oracle Database Reference for more information about
RESULT_CACHE_MAX_SIZE -
Oracle Database Reference for more information about
RESULT_CACHE_MAX_RESULT -
Oracle Database Performance Tuning Guide for more information about result cache concepts
-
Oracle Database PL/SQL Packages and Types Reference for more information about the
DBMS_RESULT_CACHEpackage -
Oracle Database Reference for more information about
V$RESULT_CACHE_STATISTICS -
Oracle Database Reference for more information about
V$RESULT_CACHE_MEMORY -
Oracle Database Reference for more information about
V$RESULT_CACHE_OBJECTS -
Oracle Database Reference for more information about
V$RESULT_CACHE_DEPENDENCY
8.12.5.8 Hot-Patching PL/SQL Units on Which Result-Cached Functions Depend
When you hot-patch a PL/SQL unit on which a result-cached function depends (directly or indirectly), the cached results associated with the result-cached function might not be automatically flushed in all cases.
For example, suppose that the result-cached function P1.foo() depends on the package subprogram P2.bar(). If a new version of the body of package P2 is loaded, the cached results associated with P1.foo() are not automatically flushed.
Therefore, this is the recommended procedure for hot-patching a PL/SQL unit:
Note:
To follow these steps, you must have the EXECUTE privilege on the package DBMS_RESULT_CACHE.