Über unsMediaKontaktImpressum
Ulrike Schwinn 24. Januar 2017

In-Memory-Technologien in der Oracle-Datenbank

Datenbank-Memory effizient einzusetzen, ist eine der "billigsten" Methoden um Datenbanken zu tunen. Was ist günstiger als die vorhandenen Ressourcen richtig zu nutzen? Oracle setzt auf den In-Memory-Trend und bietet seit jeher spezielle Techniken und Technologien an, um Daten effizient im Memory zu speichern. Effektive Lagerung im Datenbank-Cache ist dabei "groß geschrieben", sodass beispielsweise "heiße Daten" im schnellen Zugriff sind.

Um bestimmte Bereiche und Applikationen noch besser bei der Ablage im Cache zu unterstützen, wurden zusätzliche Techniken in den letzten Jahren implementiert. So können Resultate von Statementausführungen oder PL/SQL-Funktionen ebenso den Cache effizient nutzen, wie Tabellen, die mit "Full Table Scan"-Operationen abgefragt werden. Besonders auch mit der Oracle Database In-Memory-Technologie ist eine weitere interessante Neuigkeit hinzugefügt worden, die besonders bei analytischen Abfragen von großem Vorteil sein kann. Dabei zeichnet sie sich nicht nur durch eine neue Form des Caches aus, sondern profitiert zusätzlich von speziellen optimierten Statementzugriffen.

Da die Beschreibung aller Techniken den Artikel sprengen würde, werden in den folgenden Abschnitten ausgewählte spezielle Techniken und ihre Anwendungsfälle beschrieben.

Der Ergebnis Cache für sich wiederholende Abfragen?

Schon seit Oracle Database 11g gibt es einen neuen Cache-Bereich im Shared Pool, der speziell für Ergebnismengen reserviert ist: den sogenannten Result Cache. Ergebnisse von Statements, die den Result Cache nutzen, werden bei der Ausführung im Result Cache abgelegt und bei den Folgeausführungen wiederverwendet. Die Ausführungszeit reduziert sich dabei drastisch. Um konsistente Abfragen zu garantieren, wird bei Änderungen an den Tabellenwerten der Cache automatisch invalidiert. Der Result Cache kann dabei client- oder serverseitig Verwendung finden. Eine clientseitige Verwendung setzt die Nutzung von OCI Calls voraus.

Der Result Cache ist kein Allheilmittel für alle möglichen langsam laufenden Abfragen. Wie bei allen Techniken, sollte ein bestimmtes Anwendungsprofil erfüllt sein. So können beispielsweise langlaufende, rechenintensive SQL-Abfragen und PL/SQL-Konstrukte, die vorhersehbar sind und sich häufig wiederholen, von den Result Caches profitieren. Die Ergebnismenge sollte dabei gleichbleibend und deterministisch sein; also eine geringe DML-Aktivität auf den zugrundeliegenden Tabellen aufweisen.

Zur initialen Konfiguration ist die Einstellung folgender Parameter erforderlich: Mit dem Parameter RESULT_CACHE_MAX_SIZE wird die Gesamtgröße des reservierten Bereichs für den Result Cache im Shared Pool festgelegt. Dabei wird der Speicher für Ergebnisse von SQL-Abfragen UND auch für Ergebnisse von PL/SQL-Funktionen reserviert. Wird dieser Parameter auf den Wert 0 gesetzt, ist der Result Cache ausgeschaltet.

RESULT_CACHE_MAX_RESULT legt den prozentualen Anteil am gesamten Result Cache für die einzelnen Ergebnisse fest. Beide Parameter benötigen das ALTER SYSTEM-Privileg. Wird auf Remote-Objekte zugegriffen, kann mit dem Parameter RESULT_CACHE_REMOTE_EXPIRATION festgelegt werden, wie lange in Minuten das Resultat im Cache verbleibt. Dieser Parameter ist mit ALTER SESSION oder ALTER SYSTEM einstellbar. Einschalten läßt sich der Result Cache dann über die Session-Einstellung FORCE mit dem Parameter RESULT_CACHE_MODE, über das Tabellenattribut RESULT_CACHE (MODE FORCE) oder feingranular über den Hint RESULT_CACHE.

SELECT /*+ result_cache */ a.department_id         "Department",
       a.num_emp/b.total_count "%_Employees",
       a.sal_sum/b.total_sal   "%_Salary"
FROM (
  SELECT department_id,
  COUNT(*)       num_emp,
  SUM(salary)    sal_sum?
 FROM employees
 GROUP BY department_id) a, 
(
SELECT
  COUNT(*)    total_count,
  SUM(salary) total_sal
 FROM employees 
 ) b
ORDER BY a.department_id;

Die Operation "RESULT CACHE" im Ausführungsplan zeigt an, dass der Result Cache für den Top (obersten) SELECT-Zweig erzeugt bzw. bei wiederholter Ausführung auch verwendet wird. Handelt es sich dabei um eine wiederholte Ausführung, hat sich die Ausführungszeit stark reduziert und es sind keine "Logical Reads" (hier "consistent gets") mehr erforderlich.
Möchte man den Ergebnis Cache in PL/SQL aktivieren, muss der Entwickler den PL/SQL leicht modifizieren. Folgende Beispiele zeigen die Syntax mit und ohne Result Cache.

Ohne Result Cache:

CREATE OR REPLACE FUNCTION customer_sales(cust_id_in IN number)
RETURN number 
IS

Mit Result Cache:

CREATE OR REPLACE FUNCTION customer_sales(cust_id_in IN number)
RETURN number result_cache
IS

Marek-Anton Mierzwa (Drägerwerk AG & Co. KgaA) hat dazu einen interessanten Erfahrungsbericht verfasst [1]. Dort beschreibt er, wie die Gesamtperformance der Datenbank enorm gesteigert werden konnte, nachdem die Authentifizierungsabfragen der Rest Module mit dem PL/SQL Result Cache versehen waren.  

Bei der Anwendung sollten allerdings folgende Regeln berücksichtigt werden:

  • Nur gespeicherte Funktionen sind möglich. Auch sind keine anonymen Blöcke und keine Pipelined Table Functions möglich.
  • Funktionen müssen deterministisch sein.
  • Dictionary Tables, Temporary Tables, Sequences sind nicht erlaubt.
  • Nicht erlaubt sind: OUT- oder IN OUT-Parameter; IN-Parameter als LOBs, REF CURSOR, Collections, Objekte oder Records. Der Return-Typ kann kein LOB, REF CURSOR, Objekt oder Record sein.

Monitoren lässt sich der Status und die Verwendung der Result Caches sehr gut über spezielle Views wie V$RESULT_CACHE_OBJECTS und V$RESULT_CACHE_STATISTICS. Mit dem Package DBMS_RESULT_CACHE lassen sich sogar Memory-Reports erzeugen, die Result Caches invalidieren, flushen oder sogar die Result Caches umgehen.

Automatic Big Table Caching für Full Table Scans

Bei "Full Table Scan"-Operationen nutzt die Oracle-Datenbank einen internen Algorithmus für die Verwendung über den Buffer Cache. Ist die Tabelle klein (SMALL), wird beim Zugriff der Buffer Cache verwendet. Ist die Tabelle hingegen groß (LARGE), erfolgen "Direct Path Reads". Dies bedeutet, es wird direkt von den Datendateien in die PGA gelesen. Der Parameter _small_table_threshold legt die untere Grenze für die Größe von kleinen (SMALL) Tabellen fest. In Oracle Database 12c werden darüberhinaus weitere interne Kriterien hinzugezogen, um zu bestimmen, welche Tabellen über den Cache zwischengelagert werden. Um unabhängig von diesem gerade beschriebenen Standardverhalten des Buffer Caches bei parallelen und seriellen "Full Table Scans" zu sein, ist in Oracle Database 12c ein neuer Cache-Bereich im Buffer Cache eingeführt worden – der sogenannte Automatic Big Table Caching (auch kurz ABTC).

Die Idee dahinter ist einfach: Ein gewisser Teil des Buffer Caches wird für die Speicherung großer Objekte oder Teile davon reserviert, sodass die Abfragen vom Caching profitieren können. Statt "Direct Path Reads" wird dann der Big Table Cache verwendet. Um zu entscheiden, welche Objekte den Big Table Cache verwenden können, nutzt ABTC mehrere Kriterien. Entscheidend für die Nutzung ist dabei nicht nur die Größe des Objekts und die Größe des Big Table Caches. Im Unterschied zum Standard Buffer Cache-Verhalten, das auf dem Block Level orientierten LRU Algorithmus basiert, spielt hier die "Temperatur" der Objekte (nicht Blöcke) bei der Nutzung des Big Table Caches die Hauptrolle. Wichtig zu wissen ist, dass ABTC in Oracle Real Application Clusters (Oracle RAC)-Umgebungen nur mit Parallel Query unterstützt wird; in Single Instance-Umgebungen kann ABTC auch mit seriellen Abfragen verwendet werden.

Das Setup dazu ist einfach und im laufenden Betrieb möglich. Eingeschaltet wird das ABTC im Single Instance-Umfeld über den dynamischen Initialisierungsparameter DB_BIG_TABLE_CACHE_PERCENT_TARGET. Dieser Parameter reserviert einen dedizierten Anteil am Buffer Cache (in Prozent). Kontrollieren kann man den Vorgang über die beiden speziellen V$ Views V$BT_SCAN_CACHE und V$BT_SCAN_OBJ_TEMPS.

SQL> SELECT bt_cache_alloc, bt_cache_target, object_count, memory_buf_alloc,
      min_cached_temp FROM v$bt_scan_cache;
BT_CACHE_ALLOC BT_CACHE_TARGET OBJECT_COUNT MEMORY_BUF_ALLOC
-------------- --------------- ------------ ----------------
    .400005755              40            3            50685
1  rows processed

SQL> SELECT o.object_name, cached_in_mem, size_in_blks, policy, temperature
     FROM v$bt_scan_obj_temps bt, dba_objects o
     WHERE bt.dataobj#=o.object_id;

OBJECT_NAME            CACHED_IN_MEM SIZE_IN_BLKS     POLICY TEMPERATURE
--------------------   ------------- ------------ ---------- -----------
FACT_PP_OUT_ITM_XXX            41700        44878   MEM_PART      185000
AB_ELEMENT_RELA                 2644         2644       DISK        1000
SALES_COPY                         0        35421       DISK        5000

Die Tabelle FACT_PP_OUT_ITM_XXX ist fast vollständig im Memory (s. Policy MEM_PART); die Tabellen SALES_COPY und AB_ELEMENT_RELA hingegen werden weiterhin von Disk gelesen (s. Policy DISK). Die Entscheidung über das Cachen der Tabellen wird über den Spaltenwert TEMPERATURE gesteuert. Die minimale Temperatur liegt bei 1000. Bei jedem Zugriff auf ein Objekt erhöht die Datenbank die Temperatur des entsprechenden Objekts. Ein Objekt im Big Table Cache kann nur von einem Objekt mit höherer Temperatur verdrängt werden. Ist der Big Table Cache nicht ausreichend groß – wie in unserem Fall – können nur die Objekte mit der höchsten Temperatur gespeichert werden. Dabei kommt auch ein teilweises Cachen des Objekts in Frage. Soll auch die Tabelle SALES_COPY im ABTC liegen, kann beispielsweise die Größe des Big Table Caches dynamisch erhöht werden.

Markus Geis (Institut für Notfallmedizin und Medizinmanagement) beschreibt in seinem DOAG-Anwenderbericht die Vorteile der Verwendung speziell im Fall von partitionierten Tabellen. Teilweise haben sich dabei die Laufzeiten auf weniger als ein Drittel der Zeit reduziert [2]

Die gesamte Datenbank im Cache? – Full Database Caching

Normalerweise entscheidet die Datenbank selbst in Abhängigkeit von Größe und Art der Nutzung des Objekts, wie der Cache verwendet wird. Der Cache unterliegt dabei unterschiedlichen Algorithmen, was die Dauer und die Lagerung der Blöcke im Buffer Cache angeht, wie oben schon beschrieben wurde. Large Objects (auch LOBs) – also SecureFiles oder BasicFiles (in der 12c-Terminologie) – werden dabei standardmäßig nicht im Cache gespeichert. Die Speicherung eines LOBs im Cache erfolgt nur unter der Bedingung, dass explizit vorab das Speicherattribut mit einem DDL-Befehl auf CACHE gesetzt wurde.

Neu in 12c ist ein automatischer Full Database Caching Mode. Falls das Memory ausreichend für die gesamte Datenbank ist und eigene interne Regeln erfüllt sind, werden alle Tabellen als SMALL-Tabellen angesehen und im Cache gelagert. Möchte man unabhängig von diesen Regeln sein, kann man diesen Mode auch forcieren. Das Konzept nennt sich dann Force Full Database Caching. Die Idee dahinter ist im Prinzip die gleiche wie beim automatischen Full Database Caching: Ist der Cache groß genug, um alle Objekte im Cache zu speichern, können alle Objekte im Cache gelagert werden – einschließlich der LOB-Objekte. Um den Full Database Mode zu nutzen, muss dieser zusätzlich im MOUNT-Stadium der Datenbank separat eingeschaltet werden. Dies bedeutet auch, dass die Information im Control File gespeichert wird. Daher ist es sinnvoll, direkt nach dem Umsetzen des Modus ein Backup vom Controlfile zu erstellen.

SQL> startup mount;

SQL> ALTER DATABASE FORCE FULL DATABASE CACHING;
Database altered.

-- Ausschalten mit
-- ALTER DATABASE NO FORCE FULL DATABASE CACHING;

SQL> SELECT force_full_db_caching FROM v$database;
FOR
---
YES

Die Alert-Datei gibt dann Auskunft darüber, ob der Modus erfolgreich eingeschaltet werden konnte.

Completed: ALTER DATABASE  MOUNT
2015-12-15 02:56:03.396000 -08:0
alter database force full database caching
Completed: alter database force full database caching

Um Missverständnisse zu vermeiden: Nach der Konfiguration einer Datenbank im Force Full Database Mode werden die Objekte nicht automatisch in den Cache verlagert. Es muss zuerst ein Zugriff auf die Objekte erfolgen. Dabei werden auch LOBs mit der Einstellung NOCACHE geladen; dies ist beim normalen Caching nicht der Fall.

Bevor man Force Full Database Caching verwendet, sollte man sicherstellen, dass ausreichend Memory vorhanden ist. Bei Nutzung von MEMORY_TARGET oder SGA_TARGET kann sich die Größe des Buffer Cache ändern. Um dies zu verhindern, gilt auch hier die Empfehlung: Verwenden Sie DB_CACHE_SIZE, um ein Minimum zu garantieren. Häufig wird die Frage gestellt, was passiert, wenn die Datenbank wächst und die Speicherplatzanforderungen den Buffer Cache übersteigen? Wichtig zu wissen ist: Der Modus wird nicht automatisch umgeschaltet. Man wird wieder "Physical Reads" feststellen. Allerdings wird eine Information in der Alert-Datei notiert.

Force Full Database Caching eignet sich hervorragend für kleine Datenbanken, deren genutzter Speicherplatz in den Buffer Cache passt. So kann man sehr einfach die Datenbank-Performance von Full Table Scans und Zugriffen auf Large Objects erhöhen. Keine Änderungen an den Abfragen oder Segmenten sind dazu erforderlich. Dieses Feature steht übrigens wie auch das Automatic Big Table Caching in allen Editionen bzw. Cloud-Ausprägungen der Datenbank zur Verfügung und ist somit auch gut geeignet für eher kleinere Datenbanken.

Der In-Memory Column Store

Traditionell werden die Daten im Buffer Cache im sogenannten Row-Format gespeichert. Zeilenformate (Row-Formate) sind ideal für Online-Transaktionen, da sie schnelle Zugriffe auf alle Spalten einer Zeile gewähren. Beim Spaltenformat werden die Spalten hingegen in einer speziellen Spaltenstruktur gespeichert. Ideal ist diese Speicherform für analytische Abfragen, in denen wenige Spalten aber eine große Datenmenge abgefragt werden. Was passiert aber bei DML-Abfragen? Beim Zeilenformat kann eine Zeile schnell und effizient mit einer Operation verarbeitet werden, Spaltenformate hingegen eignen sich nur wenig für zeilenbasierte Operationen. Die neue Oracle Database In-Memory-Option bietet hier das beste von beidem: Spaltenformat-Ablage, der Column Store, in einem effektiven komprimierten Format für bestimmte ausgewählte Objekte, um analytische Abfragen zu beschleunigen und simultane Speicherung im Buffer Cache, sobald DML-Operationen oder andere Operationen dies erfordern.

Das Konfigurieren und die Nutzung ist recht einfach. Wie bei den anderen Pools muss ein Bereich dafür festgelegt werden. Dies geschieht mit dem Parameter INMEMORY_SIZE, der ab Oracle Database 12.2 auch dynamisch "on the fly" konfiguriert werden kann. Der Column Store besteht dabei aus zwei verschiedenen Poolarten: der 1 MB-Pool für die Daten und der 64K-Pool für die Metadaten.

SQL> select pool, alloc_bytes, used_bytes, populate_status
      from v$inmemory_area;
POOL                 ALLOC_BYTES   USED_BYTES   POPULATE_STATUS
-------------------- ------------ ------------  ---------------
1MB POOL                854589440    674234368  DONE
64KB POOL               201326592      5832704  DONE    

Wie kommen die Daten in den Pool? Die ausgewählten Objekte (Tabellen, Materialisierte Views, Partitionen oder Subpartitionen) werden über ein CREATE- oder ALTER-Kommando mit speziellen Attributen belegt, die die Speicherung im Column Store (INMEMORY), die Komprimierungsart (MEMPCOMPRESS) und die Priorität (PRIORITY) der Speicherung festlegen.

ALTER TABLE customers INMEMORY MEMCOMPRESS FOR QUERY LOW PRIORITY critical;

Verschiedene In-Memory-Komprimierungsarten sind dabei für verschiedene Charakteristiken von Workloads optimiert. Dies bedeutet, dass nicht allein die Einsparung von Speicherplatz, sondern auch die Art der Anwendung eine Rolle bei der Wahl des richtigen In-Memory-Komprimierungstyps spielt. "MEMCOMPRESS FOR QUERY LOW" liefert beispielsweise höhere Platzeinsparungsraten als "MEMCOMPRESS FOR DML". Allerdings sollte der Komprimierungstyp "MEMCOMPRESS FOR DML" bei hohen Datenmanipulationsraten immer dem Komprimierungstyp "MEMCOMPRESS FOR QUERY LOW" vorgezogen werden. Es macht natürlich nur Sinn, ein Objekt im Column Store zu platzieren, wenn ausreichend Platz zur Verfügung steht. Advisories können bei der Vorausberechnung der Größenordnung im Column Store helfen.

Danach werden die Daten je nach Priorität entweder von einem Hintergrund-Prozess oder nach einem ersten Zugriff im Pool gespeichert. Einmal gespeichert wird das Objekt nicht mehr verdrängt. Eine explizite Auslagerung mit dem entsprechenden ALTER-Kommando ist natürlich immer möglich. Ausgezeichnet überwachen lässt sich der Inhalt des Column Stores beispielsweise auch über die View V$IM_SEGMENTS.

SQL> SELECT v.segment_name name, v.par-ition_name partition,
            v.bytes/1024/1024 orig_M, v.inmemory_size/1024/1024  in_mem
            v.inmemory_compression comp, v.bytes_not_populated not_pop,
       v.inmemory_priority prio
    FROM   v$im_segments v 
NAME        PARTITION           ORIG_M IN_MEM_M COMP          NOT_POP PRIO
---------- -------------------- -------- --------- ------------- ------- ---- 
...
SALES        SALES_Q2_1999             8    1.125 FOR QUERY LOW        0 NONE
SALES        SALES_Q1_1999             8    1.125 FOR QUERY LOW        0 NONE
SALES        SALES_Q3_2001             8    1.125 FOR QUERY LOW        0 NONE
SALES        SALES_Q1_2001             8    1.125 FOR QUERY LOW        0 NONE
CUSTOMERS                             13    4.125 FOR QUERY LOW        0 CRITICAL
CUSTOMER                              64    5.125 FOR QUERY LOW        0 CRITICAL
SALES        SALES_Q4_2001             8   5.1875 FOR QUERY LOW        0 NONE

Wie bei den anderen Memory-Techniken, ist auch hier keine Änderung an der Applikation erforderlich. Wenn der Zugriff im Column Store sinnvoll ist, wird der Optimizer automatisch – sogar mit speziell für den Column Store entwickelten Operationen – die Abfrage durchführen. Spezielle Techniken und die Verwendung von SIMD-Operationen (Single Instruction for Multiple Data values), die durch die aktuelle Mikroprozessortechnik möglich wird, führen dabei zu extrem schnellen Resultaten und beschleunigen die Abfragen um Faktoren. Für Testzwecke eignet sich dabei der Session-Parameter INMEMORY_QUERY, mit dem man den Zugriff auf den Column Store erlauben oder verhindern kann. Besonders geeignet ist der Column Store für analytische Abfragen nämlich für Scannen von vielen Zeilen und die Anwendung von Filtern wie  =, <, >, IN etc. Abfragen einer Teilmenge von Spalten (zum Beispiel 5 von 100 Spalten einer Tabelle), Joins von kleinen Tabellen mit einer großen Tabelle oder die Filterung von vielen Zeilen und Abfragen mit Operationen wie min, max, sum, group, distinct etc. sind nur einige Beispiele für Abfragen, die profitieren können.

Ein Beispiel für den erfolgreichen Einsatz aus dem SAP-Umfeld beschreibt Harald Wolf (Villeroy & Boch AG) in seinem Anwenderbericht. Oracle Database In-Memory wurde für SAP NetWeaver BW und CRM erprobt und wird nun im Anschluss produktiv eingesetzt werden. Beim Test mit dem In-Memory Column Store konnte die Laufzeit einiger Statements enorm reduziert werden (z. B. von 50 auf 1.5 Sekunden oder von 72 auf 2.5 Sekunden) [3].

In Oracle Database 12.2 sind zusätzlich einige Features ergänzt worden. Beispielsweise ist nun ein Fast-Start möglich, JSON-Dokumente erfahren ein optimiertes Handling, häufig verwendete Expressions können materialisiert und für In-Memory-Zugriffe verwendet werden und ILM Policies stehen für die In-Memory-Verlagerung zur Verfügung.

Fazit

In-Memory-Techniken in der Oracle-Datenbank einzusetzen ist einfach und risikolos. Ist ausreichendes Memory vorhanden, kann man die passenden Techniken einfach ausprobieren. Auch die Kombination der verschiedenen Technologien ist zu empfehlen. Die SQL-Abfragen bleiben erhalten und müssen in der Regel nicht angepasst werden. Tabellenattribute, Sessioneigenschaften oder einfach nur das Bereitstellen einer Technik reicht im Normalfall zum Einsatz aus. Auch die Verwendung weiterer Datenbankmechanismen wie z. B. im Bereich Security, Hochverfügbarkeit usw. werden wie gewohnt unterstützt.

Das optimierte Zusammenspiel mit den Technologien aus dem Data Warehouse- und Analytics-Umfeld wie Partitionierung und Parallelisierung ist garantiert. Die Verwaltung und Verwendung einer Oracle-Datenbank unterscheidet sich also nicht von den bislang genutzten Methoden. Die Arbeit der Administratoren bzw. der Anwendungsentwickler ändert sich nicht, kein Mehraufwand ist zu erwarten. Möchte man mehr zu den einzelnen Themen erfahren, stehen zahlreiche White Paper und Blogeinträge zur Verfügung [4,5].  

Autorin
Das könnte Sie auch interessieren

Neuen Kommentar schreiben

Kommentare (0)