Suchen mit SQL LIKE: Performance, Case- und Umlaut-Insensitive Suche
Erscheinungsmonat |
APEX-Version |
Datenbankversion |
August 2012 |
alle |
ab 9.2 |
In jeder APEX-Anwendung wird mit SQL-Abfragen gesucht - und zwar stets dann, wenn
man eine WHERE-Klausel verwendet. Für die vom Endanwender eingestellten Filter eines
interaktiven Berichten muss man hier nicht viel
machen; APEX generiert die SQL-WHERE-Klausel selbstständig. Möchte man jedoch im
Berichts-SQL selbst eine WHERE-Klausel einbauen oder verwendet man klassische Berichte,
so kann es ganz hilfreich sein, den einen oder anderen Such-Trick zu kennen.
Für den ersten "klassischen" APEX-Bericht auf einer Anwendungsseite kann man die Berichtssuche aktivieren (Abbildung 1).
Abbildung 1: Berichtssuche aktivieren für einen klassischen Bericht
APEX generiert daraufhin folgende SQL-Abfrage
Die bei Berichtserstellung angegebene SQL-Abfrage wird nochmals
"eingerahmt": Die äußere SQL-Abfrage implementiert die "Suche"
mit Hilfe der SQL-Funktion INSTR. Damit findet eine Teilstringsuche statt. Allerdings
wird für diese niemals ein Index verwendet - bei großen Tabellen kann eine solche
Suche also schonmal etwas länger dauern. Die folgenden Tests wurden mit SQL*Plus
gemacht; natürlich kann man die gleichen Effekte auch mit dem SQL Developer oder
dem APEX SQL-Workshop erreichen. Für die Tests wurde eine Tabelle BIGEMP erstellt, das ist die Tabelle EMP mit mehreren Millionen Zeilen - lediglich JONES kommt nur einmal vor.
Mehr als zwei Sekunden ist für eine solche Abfrage sicherlich
zu lang. Der Ausführungsplan zeigt, dass der Index nicht verwendet
werden konnte.
Und das ist logisch - denn die INSTR-Funktion findet ja nicht nur
einfach den Teilstring, sie liefert sogar die Position zurück, an der dieser
gefunden wurde. Ein Index kann hier nicht helfen. Eine Alternative ist der
SQL LIKE Operator ...
Der Ausführungsplan zeigt, dass der Index genutzt wurde ...
Allerdings findet diese Abfrage nur die Zeilen, in denen der ENAME tatsächlich
mit dem Suchstring beginnt. Sucht man dagegen nach einem Teilstring am
Ende des ENAME, findet diese LIKE-Klausel nichts mehr - dann muss man den Platzhalter an
den Anfang stellen.
Nun findet ein Full Table Scan statt, denn der Index kann logischerweise
nicht genutzt werden - schließlich ist der Anfangsbuchstabe der gesuchten
ENAME gar nicht bekannt, es gibt also keine Einstiegspunkte
in den Index. Der Datenbank bleibt also nichts übrig, als alle
Zeilen durchzuarbeiten.
Aber auch diese Abfrage lässt sich in der Tat durch einen Index unterstützen -
ein solcher müsste die Spalteninhalte lediglich "rückwärts" enthalten. Zuerst
brauchen wir also eine Funktion, die eine Zeichenkette "umdreht" - wir nennen sie
STRING_REVERSE.
Für die Experten: Es gibt sogar eine eingebaute Funktion namens REVERSE - die macht genau
das gleiche, ist aber nicht dokumentiert. Wer also keine Angst vor undokumentierten
Funktionen hat, kann auch diese nutzen. Als nächstes gilt es, den Index aufzubauen.
Nun kann man den Index nutzen. Allerdings muss die LIKE-Abfrage dazu
etwas anders formuliert werden ...
Wiederum ging das recht flott. Der Ausführungsplan zeigt, dass der Index
auch tatsächlich genutzt wurde.
Beides kann nun kombiniert werden ...
... was zur Nutzung beider Indizes führt ...
Eine Teilstringsuche "in der Mitte", also ein LIKE '%ONE%' führt aber in
jedem Fall zu einem Full Table Scan. Denn da die Wildcard nun auf beiden Seiten
steht, findet die Datenbank für beide Indizes keine Einstiegspunkte - sie muss die
Tabelle also wieder komplett durcharbeiten.
Was bedeutet das nun für die APEX-Anwendung?
Zunächst sollte man den Endanwender die Wildcards selbst eingeben lassen. Wenn
man dabei möchte, dass der Endanwender statt des Prozentzeichens einen Stern nutzen kann,
so ist das mit TRANSLATE völlig unproblematisch. Der Nutzer hat es dann selbst in der
Hand: Setzt er die Wildcard nur vorne oder nur hinten, so ist die Abfrage (dank Indexnutzung)
sehr schnell. Verwendet er Wildcards vorne und hinten, so ist die Suche "mächtiger", kostet
aber auch mehr Zeit.
Die Abfrage des "klassischen" APEX Berichts kann nun also entsprechend geändert werden.
Dazu sind folgende Aktionen nötig:
- Es braucht einen "normalen" Index auf die Spalten ENAME und JOB
- Es braucht einen "reverse" Index auf die Spalten ENAME und JOB
Schließlich stellen wir die SQL-Abfrage entsprechend um:
Der APEX-Bericht funktioniert nun wie vorher, allerdings muss nun die Wildcard
eingegeben werden. Wird diese
nur vorne oder nur hinten angegeben, so arbeitet die Suche auch bei sehr
großen Tabellen performant.
Abbildung 2: APEX-Bericht mit neuer SQL-Abfrage: Nun muss die Wildcard aktiv verwendet werden
Allerdings hat der Bericht noch einen Schönheitsfehler. Wenn man den Suchbegriff in
Kleinbuchstaben eingibt, wird nichts gefunden. Und wo wir gerade dabei sind: Gerade bei
Daten in europäischen Sprachen wäre es gut, wenn man Akzent-Insensitiv suchen könnte - man
sucht nach Muller - und findet auch Müller. Hierfür gibt es in der Datenbank mittlerweile
eigene Session-Parameter - mit einem ALTER SESSION kann das Suchverhalten also umgestellt
werden. Allerdings ist es in APEX oft problematisch, Session-Parameter umzustellen, daher
sei hier ein anderer Weg gezeigt.
Die in die Datenbank eingebaute Funktion NLSSORT "normalisiert" eine Zeichenkette - das
heißt, die Zeichen werden in ihre Grundformen im "Lower Case" umgewandelt. Dazu ein Beispiel
Die Rückgabe ist ein RAW ... wandelt man das wiederum explizit in ein VARCHAR2
um, sieht das Ergebnis so aus.
Und analog zur Vorgehensweise mit STRING_REVERSE kann man nun auch Indizes
hierfür aufbauen. Damit die SQL-Abfrage leserlich bleibt, brauchen wir
zunächst zwei Funktionen: PREP_STRING und PREP_STRING_REV.
Als nächstes bauen wir die Indizes auf die Spalten ENAME und JOB neu.
Zum Schluß tauschen wir wiederum die SQL-Abfrage aus.
Die Suche im klassischen APEX-Bericht hat sich nun, gegenüber der APEX-Standardimplementierung,
ein gutes Stück verbessert.
Abbildung 3: Nun kann auch Case- und Umlaut-Insensitiv gesucht werden
- Es kann nun auch Umlaut-Insensitiv gesucht werden
- Der Nutzer kann entscheiden, ob er mit oder ohne Wildcard suchen möchte
- Wird die Wildcard nur vorne oder nur hinten verwendet, so ist die Suche auch auf großen Datenmengen sehr performant, da Indizes genutzt werden können.
Die Möglichkeiten von "Standard SQL" sind damit erschöpft, nicht aber die Möglichkeiten
der Oracle-Datenbank. Mit Hilfe der Volltextengine Oracle TEXT können Sie die Suche
um "Volltextfeatures" wie linguistische Suche, Ähnlichkeitssuche und "echte" Teilstring-Suche,
also "%SUCHE%" erweitern. Mehr dazu finden Sie in den Tipps der APEX-Community zum Thema
oder im deutschsprachigen Oracle TEXT Blog.
Zurück zur Community-Seite
|