Heute geht es um den mit Oracle12c neu eingeführten Query Filter Cache. Das ist
ein Ergebnis-Cache, speziell für Oracle TEXT Abfragen. Ergebnisse von Oracle TEXT-Abfragen
werden - ganz ähnlich zum "normalen" SQL Result Cache - in einem separaten Hauptspeicherbereich
abgelegt bei Bedarf wiederverwendet. Kann ein Ergebnis aus dem Cache geholt werden, muss die
eigentliche Oracle TEXT Abfrage nicht mehr ausgeführt werden; die Antwortzeit sollte dann
wesentlich besser sein.
Gut geeignet ist der Query Filter Cache zum nachträglichen Filtern von Abfrageergebnissen. Dabei
kann es um das Anwenden von Zugriffsregeln gehen (Sicherheit); aber auch Anwendungen, die
die nachträgliche An- und Abwahl von Dokumentkategorien erlauben, können so durch einen
Ergebniscache unterstützt werden. Denn jede An- oder Abwahl einer Kategorie (bspw. durch
Setzen einer Checkbox in der Anwendung) führt ja zu einer erneuten Ausführung der Query. Nutzt
man den Query Filter Cache, so müssen die Ergebnisse nur noch aus dem Cache geholt
und nachgefiltert werden. Das folgende Beispiel stellt den Query Filter Cache vor - los geht's
wie immer mit dem Erstellen einer Tabelle.
create table texttabelle( id number(10), ressort varchar2(20), dokument clob ) / insert into texttabelle values ( 1, 'Politik', 'A-Partei gewinnt Wahl in Hansestadt'); insert into texttabelle values ( 2, 'Panorama', 'Terror in Nahost: Kriminalität steigt immer weiter an'); insert into texttabelle values ( 3, 'Wirtschaft', 'Wirtschaft: Erneuter Gewinnzuwachs in diesem Jahr'); insert into texttabelle values ( 4, 'Sport', 'Olympia rückt näher: Der Fackellauf ist in vollem Gange'); insert into texttabelle values ( 5, 'Politik', 'Wer wird US-Präsident? Obama und Clinton machen Wahlkampf'); insert into texttabelle values ( 6, 'Politik', 'Papst bestürzt über jüngsten Skandal!'); insert into texttabelle values ( 7, 'USA', 'Wahlkampf in den USA: Clinton und Obama LIVE zu sehen'); insert into texttabelle values ( 8, 'Wirtschaft', 'Software-Kenntnisse werden immer wichtiger'); insert into texttabelle values ( 9, 'Wirtschaft', 'Umfrage: Alle wollen mehr Geld!'); insert into texttabelle values (10, 'Panorama', 'Der Papst liest seine erste Messe in den USA!'); commit /
In der Spalte DOKUMENT soll gesucht werden, anhand der Spalte RESSORT soll dann
nachträglich gefiltert werden. Um den Query Filter Cache nutzen zu können, muss
eine explizite Storage Preference erstellt und im Index genutzt werden. Dabei wird
die Größe des Cache mit dem Attribut QUERY_FILTER_CACHE_SIZE in Bytes angegegen. Dieser Speicherbereich wird dann in der
SGA allokiert - die Größe sollte also mit Bedacht - und nach Absprache mit dem
DBA bestimmt werden.
begin ctx_ddl.create_preference('my_idx_storage', 'basic_storage'); ctx_ddl.set_attribute('my_idx_storage', 'query_filter_cache_size', '10M'); end; / create index idx_text on texttabelle (dokument) indextype is ctxsys.context filter by ressort parameters ('storage my_idx_storage sync (on commit)') /
Die Data Dictionary View CTX_FILTER_CACHE_STATISTICS gibt Informationen über den
Cache - Zu Beginn stehen alle Einträge natürlich auf Null.
SQL> select * from ctx_filter_cache_statistics FCS_INDEX_OWNER FCS_INDEX_NAME FCS_PARTITION_NAME FCS_SIZE FCS_ENTRIES FCS_REQUESTS FCS_HITS --------------- -------------- ------------------ ---------- ----------- ------------ ---------- TEXT IDX_TEXT 0 0 0 0
Nun geht es daran, den neuen Cache zu nutzen. Das geschieht zunächst, ganz normal, mit
Hilfe des Oracle TEXT SQL-Operators CONTAINS. In diesem wird nun aber die
spezielle Abfragefunktion CTXFILTERCACHE verwendet - und zwar wie folgt.
select * from texttabelle
where contains(dokument, 'ctxfiltercache((Wirtschaft), true, true)') > 0;
ID RESSORT DOKUMENT
---------- -------------------- ---------------------------------------------------------------------------
3 Wirtschaft Wirtschaft: Erneuter Gewinnzuwachs in diesem Jahr
Der neue Cache wird also mit dem Schlüsselwort CTXFILTERCACHE explizit angesprochen. Der erste Parameter
(Wirtschaft) ist die Text-Query, die anderen beiden bestimmen das Verhalten des Cache näher. Der
zweite Parameter (true) legt fest, ob der SCORE-Wert eines Ergebnisses ebenfalls im Cache abgelegt
werden soll. Standardmäßig steht dieser Parameter auf FALSE: Ein aus dem Cache geholtes Ergebnis
hat dann einen Score von 100. Wird der Parameter, wie oben, auf TRUE gesetzt, werden die SCORE-Werte
ebenfalls in den Cache gelegt und wiederverwendet. Der dritte Parameter bestimmt, ob nur die "TOP-N"-Ergebnisse
in den Cache gelegt werden sollen - wieviele das sind, bestimmt die Datenbank automatisch; eine manuelle
Festlegung ist nicht möglich. Um TOP-N auf TRUE zu setzen, muss auch der zweite SCORE-Parameter auf
TRUE gesetzt sein. Die Dokumentation enthält nähere Details.
Nach der ersten Ausführung der Query kann man anhand der Statistik-View schon erkennen, dass mit
dem Cache gearbeitet wurde.
SQL> select * from ctx_filter_cache_statistics FCS_INDEX_OWNER FCS_INDEX_NAME FCS_PARTITION_NAME FCS_SIZE FCS_ENTRIES FCS_REQUESTS FCS_HITS --------------- -------------- ------------------ ---------- ----------- ------------ ---------- TEXT IDX_TEXT 13096 1 1 0
Anhand von FCS_ENTRIES sieht man, dass nun eine Abfrage mit dem Cache gearbeitet hat. Es
erfolgte eine Anfrage an den Cache (FCS_REQUESTS), aber da die Abfrage zum ersten Mal abgesetzt
wurde, ergab sich noch kein Hit (FCS_HITS). Anders sieht es aus, wenn man die Abfrage nochmals
absetzt: Nun ergeben sich zwei Anfragen und ein Cache-Hit. Die Abfrage wurde also aus dem
Cache bedient.
SQL> select * from ctx_filter_cache_statistics FCS_INDEX_OWNER FCS_INDEX_NAME FCS_PARTITION_NAME FCS_SIZE FCS_ENTRIES FCS_REQUESTS FCS_HITS --------------- -------------- ------------------ ---------- ----------- ------------ ---------- TEXT IDX_TEXT 13096 1 2 1
Nun zu einem der eigentlichen Anwendungsfälle. Wir suchen in der oberen Tabelle nach Obama.
SQL> select * from texttabelle where contains(dokument, 'ctxfiltercache((Obama), true, true)') > 0 ; ID RESSORT DOKUMENT ---------- -------------------- ---------------------------------------------------------------------------- 5 Politik Wer wird US-PrSsident? Obama und Clinton machen Wahlkampf 7 USA Wahlkampf in den USA: Clinton und Obama LIVE zu sehen 2 Zeilen ausgewählt. SQL> select * from ctx_filter_cache_statistics; FCS_INDEX_OWNER FCS_INDEX_NAME FCS_PARTITION_NAME FCS_SIZE FCS_ENTRIES FCS_REQUESTS FCS_HITS --------------- -------------- ------------------ ---------- ----------- ------------ ---------- TEXT IDX_TEXT 13096 1 1 0 1 Zeile wurde ausgewählt.
Diese Abfrage liefert Ergebnisse aus zwei Ressorts. Wieder haben wir einen Request an den Cache und
(noch) keinen Hit. Nun nehmen wir aber an, dass der Anwender in der Benutzeroberfläche in der
Checkbox für die Ressorts klickt - und zwar wählt er das Ressort "USA" ab. Das führt zu einer
neuen Query, bei der ein SDATA-Ausdruck anstelle einer AND-Verknüpfung auf SQL-Ebene verwendet wird.
Dies dient der Vermeidung von Mixed Queries - was bei der Arbeit mit Oracle TEXT generell zu empfehlen ist (siehe Blog Posting Abfrage-Optimierung mit Composite Domain Index).
select * from texttabelle where contains( dokument, 'ctxfiltercache((Obama), true, true) and sdata(ressort = ''Politik'')' ) > 0; ID RESSORT DOKUMENT ---------- -------------------- -------------------------------------------------------------------------------- 5 Politik Wer wird US-PrSsident? Obama und Clinton machen Wahlkampf 1 Zeile wurde ausgewählt. SQL> select * from ctx_filter_cache_statistics; FCS_INDEX_OWNER FCS_INDEX_NAME FCS_PARTITION_NAME FCS_SIZE FCS_ENTRIES FCS_REQUESTS FCS_HITS --------------- -------------- ------------------ ---------- ----------- ------------ ---------- TEXT IDX_TEXT 13096 1 2 1 1 Zeile wurde ausgewählt.
Obgleich die Gesamt-Abfrage eine andere war, wurde der Cache angefragt und genutzt. Der
Query Filter Cache ist also eine gute Unterstützung für das nachträgliche Filtern von Oracle TEXT
Abfrageergebnissen, wie es in vielen Anwendungen mittlerweile Standard ist.
Der Filter Cache muss in der Anwendung jedoch explizit angesprochen werden; eine automatische
Nutzung für existierende Anwendungen ist nicht möglich - dazu sind die möglichen Seiteneffekte,
speziell beim Score, einfach zu wesentlich. Solange also CTXFILTERCACHE nicht innerhalb CONTAINS
verwendet wird, wird auch kein Cache genutzt. Als Entwickler muss man eine explizite Entscheidung
für die Nutzung des Cache treffen und dies die CONTAINS-Abfragen entsprechend kodieren.