Result Cache

03.
Februar
2012
Veröffentlicht von: Hildegard Asenbauer

Der Result Cache ist ein - leider auf die Enterprise Edition beschränktes - Feature, das mit Version 11g eingeführt wurde. Er ist sowohl in SQL für Select-Befehle als auch in PL/SQL für Funktionsaufrufe nutzbar. Die Idee dahinter ist in beiden Fällen, dass das Ergebnis bei der ersten Ausführung gespeichert wird und bei weiteren Aufrufen der Befehl selber nicht mehr ausgeführt, sondern das Ergebnis aus dem Cache abgerufen wird. Um Tom Kyte zu zitieren: "Everyone knows the fastest way to do something is – to not do it".

Der Result Cache ist ein - leider auf die Enterprise Edition beschränktes - Feature, das mit Version 11g eingeführt wurde. Er ist sowohl in SQL für Select-Befehle als auch in PL/SQL für Funktionsaufrufe nutzbar. Die Idee dahinter ist in beiden Fällen, dass das Ergebnis bei der ersten Ausführung gespeichert wird und bei weiteren Aufrufen der Befehl selber nicht mehr ausgeführt, sondern das Ergebnis aus dem Cache abgerufen wird. Um Tom Kyte zu zitieren: "Everyone knows the fastest way to do something is – to not do it".

Der dafür genutzte Speicherbereich - eben der Result Cache - ist Bestandteil der SGA. Um ihn nutzen zu können, muss nur seine Größe (RESULT_CACHE_MAX_SIZE ) auf einen Wert > 0 eingestellt sein.

Parameter (serverseitig)

  • RESULT_CACHE_MAX_SIZE
    Größe des Result Cache in Bytes.
    Der Default hängt von den Einstellungen für SHARED_POOL_SIZE, SGA_TARGET und MEMORY_TARGET ab

  • RESULT_CACHE_MAX_RESULT
    Anteil am Result Cache in Prozent, der maximal für einen einzigen Befehl genutzt werden darf.
    Default: 5

In einem RAC-Umfeld muss darauf geachtet werden, dass entweder auf ALLEN Instanzen RESULT_CACHE_MAX_SIZE auf einem Wert > 0 steht, oder auf keiner; sonst kann es laut Doku zu falschen Ergebnissen kommen.

SQL

In SQL gibt es zwei Wege, den Result Cache zu nutzen, entweder über den (auch auf Session-Ebene einstellbaren) Parameter RESULT_CACHE_MODE oder über den Hint RESULT_CACHE:

Steht RESULT_CACHE_MODE auf MANUAL (dem Default), dann muss die Verwendung des Result Cache explizit im Select über den Hint RESULT_CACHE angefordert werden. Steht RESULT_CACHE_MODE dagegen auf FORCE, so wird bei JEDEM Select versucht, den Result Cache zu nutzen, es sei denn, das wird explizt durch den Hint NO_RESULT_CACHE unterbunden. Zumindest eine systemweite Einstellung von RESULT_CACHE_MODE=FORCE dürfte eher nicht sinnvoll sein, da der Platz ja begrenzt ist und somit ein ständiger Turnover stattfinden würde.

Die Verwendung des Result Cache ist auch im Ausführungsplan sichtbar.

PL/SQL

Interessant ist der Result Cache vor allem im PL/SQL-Umfeld. Es kommt immer wieder vor, dass man kleine Lookup-Tabellen hat, aus denen häufig ein einzelner Wert - gekapselt in eine Funktion - ausgelesen wird. Oder man verwendet ständig die ein oder andere kleinere Hilfsfunktion (z.B. zur Formatierung oder Berechnung von Werten) für immer wieder die gleichen Werte. Musste man vor Version 11g die Performance steigern, so blieben nur Hilfskonstrukte, wie beispielsweise das Einlesen von Werten in globale Package-Variablen oder -Arrays. Der Nachteil dieses Vorgehens liegt auf der Hand: Package-Variablen behalten ihren Wert nur innerhalb der Session, und spätestens bei Web-Applikationen ist dieser Ansatz daher obsolet.

In Version 11g kann nun das Ergebnis einer Funktion im Result Cache abgelegt und wieder abgerufen werden, egal, ob es sich um eine Package-Funktion oder um eine Standalone Funktion handelt. Es muss nur in der Funktionsdeklaration angegeben werden (bei Packages sowohl im Header als auch im Body). Und da der Result Cache Bestandteil der SGA ist, nicht der PGA, ist er auch Session-übergreifend nutzbar!

Beispiel:

SET SERVEROUTPUT ON
SET ECHO ON

CREATE FUNCTION cache_it (
   p_empno  IN  NUMBER
)
   RETURN VARCHAR2
   RESULT_CACHE
   -- RELIES_ON(SCOTT.emp)  -- nur in Version 11.1 nötig
IS
   v_name   SCOTT.EMP.ename
%TYPE;BEGIN
   SELECT ename
     INTO v_name
     FROM SCOTT.emp
    WHERE empno = p_empno;

   RETURN v_name;
END;
/

DECLARE
   v_begin    NUMBER;
   v_end      NUMBER;
   v_ret      VARCHAR2 (100);
   TYPE t IS TABLE OF NUMBER
      INDEX BY PLS_INTEGER;
   v_arr      t;
BEGIN
   SELECT empno
   BULK COLLECT INTO v_arr
     FROM scott.emp;

   v_begin := DBMS_UTILITY.get_cpu_time;

   FOR i IN 1 .. 1000
   LOOP
      FOR j IN 1 .. v_arr.COUNT
      LOOP
         v_ret := cache_it (v_arr (j));
      END LOOP;
   END LOOP;

   v_end := DBMS_UTILITY.get_cpu_time;
   DBMS_OUTPUT.put_line ('Zeit: ' || (v_end - v_begin));
END;
/
-- Verwendung des Result Cache (systemweit) deaktivieren
EXEC DBMS_RESULT_CACHE.bypass(TRUE)
/
-- Verwendung des Result Cache (systemweit) wieder aktivieren
EXEC DBMS_RESULT_CACHE.bypass(FALSE)
/

DROP FUNCTION cache_it;

Ausgabe:
Zeit: 5   -- mit  Result Cache
Zeit: 54  -- ohne Result Cache
Zeit: 5   -- mit  Result Cache

Das Package DBMS_RESULT_CACHE bietet einige Verwaltungsmöglichkeiten an, wie z.B. Statusabfrage, vorübergehendes Ausschalten (s.o.), explizite Invalidierung oder, wie unten gezeigt, Erzeugung eines Reports zum Speicherverbrauch:

SET SERVEROUTPUT ON
EXEC DBMS_RESULT_CACHE.MEMORY_REPORT(detailed => TRUE)

Invalidierungen

Im obigen Beispiel wird innerhalb der Funktion auf eine Tabelle zugegriffen. Was passiert, wenn diese Tabelle nun von einer anderen Session geändert wird? In diesem Fall werden beim Commit alle davon abhängigen Ergebnisse automatisch invalidiert und bei Bedarf neu ermittelt, so dass die Funktion nie falsche Ergebnisse liefert. Wird die Tabelle innerhalb der EIGENEN Session geändert, so wird für abhängige Funktionen der Result Cache grundsätzlich so lange nicht mehr verwendet, bis die Transaktion beendet ist. Die Lesekonsistenz ist also immer gewährleistet.

In Version 11.1 musste man mit der Klausel RELIES_ON noch explizit angeben, von welchen Tabellen der Rückgabewert der Funktion abhängig ist. Hat man die Klausel vergessen, so führte das nicht zu einem Kompilierungsfehler, sondern ggf. zu falschen Resultaten. In Version 11.2 werden solche Abhängigkeiten automatisch erkannt.

Einschränkungen

Natürlich gibt es auch ein paar Einschränkungen bei der Verwendung, die aber normalerweise schon der Compiler nicht zulässt. Dazu gehören

  • OUT-Parameter sind nicht erlaubt (gespeichert werden die Werte für IN-Parameter und Ergebnisse)
  • Zulässig als IN-Parameter und Returnwert sind im wesentlichen nur skalare Datentpyen
  • Nicht zulässig bei Invoker Rights

Beispiel für Fehlermeldungen:

PLS-00999: Implementierungseinschränkung (kann temporär sein) RESULT_CACHE is disallowed on subprograms in Invoker-Rights modules

Ab Version 12c fällt die letztgenannte Einschränkung weg; dann kann der Result Cache auch bei Invoker Rights genutzt werden.

Eine genaue Auflistung aller Einschränkungen finden Sie in der PL/SQL Language Reference.

V$-Views zum Result Cache:

  • V$RESULT_CACHE_OBJECTS
  • V$RESULT_CACHE_MEMORY
  • V$RESULT_CACHE_DEPENDENCY

Viele weitere interessante Informationen hierzu erfahren Sie in unserer Opens internal link in current windowSchulung Neuerungen 11g.

SQL PL/SQL DBA

Jede Menge Know-how für Sie!

In unserer Know-How Datenbank finden Sie mehr als 300 ausführliche Beiträge zu den Oracle-Themen wie DBA, SQL, PL/SQL, APEX und vielem mehr.
Hier erhalten Sie Antworten auf Ihre Fragen.