Dienstag, 16. September 2008

Index-Synchonisierung und TRANSACTIONAL-Parameter

Eine sehr wichtige Eigenschaft jedes Textindex ist das TRANSACTIONAL Keyword, welches seit Oracle10g verwendet werden kann.
Normalerweise ist es ja so, dass Änderungen an der Dokumenttabelle im Index nicht sofort sichtbar werden, sondern erst nach dem Index Sync. Das kann man sehr schön in der View CTX_USER_PENDING nachvollziehen.
SQL> select PND_INDEX_NAME, PND_ROWID, PND_TIMESTAMP  from ctx_user_pending;

PND_INDEX_NAME                 PND_ROWID          PND_TIMESTAMP
------------------------------ ------------------ -------------------
IDX_DOKUMENT_VOLLTEXT          AAAiPsAAEAAAjUlAAD 16.09.2008 10:18:35
IDX_VOLLTEXT_2                 AAAiPsAAEAAAjUkAAA 29.07.2008 11:12:59
IDX_VOLLTEXT_2                 AAAiPsAAEAAAjUlAAD 16.09.2008 10:18:36
IDX_VOLLTEXT_2                 AAAiPsAAEAAAjUmAAD 29.07.2008 10:50:37
IDX_VOLLTEXT_2                 AAAiPsAAEAAAjUmAAE 29.07.2008 10:59:23
In einer Volltextrecherche sind diese Dokumente normalerweise nicht sichtbar; sie sind noch nicht in den Index synchronisiert. Doch was tut man, wenn die Anforderung besteht, dass alle Dokumente sofort durchsuchbar sein müssen ...?
Man könnte den Index nach jedem COMMIT synchronisieren; damit wäre die Anforderung erstmal erfüllt ... und es gibt sogar einen Parameter dafür: Beim CREATE INDEX kann als Parameter SYNC ON COMMIT mitgegeben werden. Das hat aber einen gewichtigen Nachteil:
Beim Synchronisieren (CTX_DDL.SYNC_INDEX) wird ebenfalls Wert auf möglichst kurze Laufzeit gelegt. Die neuen Informationen (die Tokens des neuen Dokumentes) werden also nicht an die Stellen in den Index eingepflegt, wo es für die Abfrageperformance optimal wäre, sondern dort, wo es am schnellsten geht: quasi "ans Ende" des Index. Die hinsichtlich Abfrageperformance "optimale" Struktur wird erst durch das Optimieren (CTX_DDL.OPTIMIZE_INDEX) erzeugt.
Eine Synchronisierung nach jedem Commit bedeutet also, dass der Index mit jedem Commit weiter "fragmentiert" - die Abfrageperformance also recht schnell immer schlechter wird. Als Faustregel kann man festhalten, dass eine Synchronisation mit so vielen Dokumenten wie möglich stattfinden sollte - auf jeden Fall aber mit mehr als einem.
Das sieht nach einem Dilemma aus: Wenn nun (siehe oben) die Anforderung besteht, dass ein neues Dokument sofort durchsuchbar sein soll, müssten wir ja nach jedem COMMIT synchronisieren - das wollen wir aber nicht, weil der Index dann zu schnell fragmentiert. Und genau hier greift der Parameter TRANSACTIONAL des Volltextindex. Ein transaktionaler Index wird wie folgt erzeugt:
create index idx_volltext on dokumente_tabelle (spalte)
indextype is CTXSYS.CONTEXT
parameters ('TRANSACTIONAL')
Bei Volltextabfragen mit der CONTAINS-Funktion auf diesen Index werden nun auch die noch gar nicht im Index befindlichen Dokumente gefunden. Wird der Parameter gesetzt, so durchsucht Oracle die noch nicht synchronisierten Dokumente (CTX_USER_PENDING) zur Abfragezeit on-the-fly.
Der Vorteil ist nun, dass man nicht mehr "den Druck hat", den Index sofort nach Einfügen eines Dokumentes zu synchronisieren - denn es ist ja auffindbar. Man kann sich nun ein geeignetes Synchronisierungsintervall überlegen, welches die Indexfragmentierung einerseits in Grenzen hält und andererseits häufig genug synchronisiert, so dass nicht zuviele Dokumente on-the-fly durchsucht werden müssen. Denn eins ist auch klar: Die Suche im Index ist auf jeden Fall günstiger als die on-the-fly Suche durch die noch nicht synchronisierten Dokumente.
Generell kann man sagen, dass der Parameter TRANSACTIONAL ab Oracle10g eine gute Sache ist - man kann ihn eigentlich generell setzen. Das Finden eines guten Intervalls zum Synchronisieren und zum Optimieren (also das Finden einer guten Strategie für die Indexwartung) bleibt jedoch weiterhin eine wichtige Aufgabe in einem Oracle TEXT Projekt.

Beliebte Postings