2009-10-15 1 views
12

Wie kann ich nach einem Teilstring in einer Zeichenfolge in Oracle suchen, ohne LIKE zu verwenden? Lassen Sie uns sagen, dass ich alle Benutzer aus einer Tabelle auswählen möchten, die den Buchstaben „z“ in ihren Nachnamen haben:Suchen nach einem Teilstring in einem String in Oracle ohne LIKE

SELECT * FROM users WHERE last_name LIKE "%z%"; 

das funktionieren würde, aber ich will mich nicht wie verwenden. Gibt es eine andere Funktion, die ich verwenden könnte?

Antwort

13

Ich vermute, der Grund, warum Sie fragen, ist die Leistung? Es gibt die instr Funktion. Aber das wird hinter den Kulissen wahrscheinlich genauso funktionieren.

Vielleicht könnten Sie in full text search suchen.

Als letzte Ressorts würden Sie Caching oder vorberechnete Spalten/eine indizierte Ansicht betrachten.

+0

Meine Vermutung ist, dass die Volltextsuche nichts kaufen wird. Es indiziert normalerweise Wörter, keine Teilstrings. – Tomalak

+0

Um ehrlich zu sein, ich habe noch nie Oracle's versucht. Ich hoffe, dass es eine Art Wildcard-System unterstützt. Ich weiß, SQL Server-Volltext tut – wefwfwefwe

+0

Ja, es ist weil Leistung. Ich suche etwas wie strstr() in PHP. –

2

Datenbanken sind stark für häufige Anwendungsszenarien optimiert (und LIKE ist einer davon).

Sie werden Ihre Suche nicht schneller finden, wenn Sie auf der DB-Ebene bleiben wollen.

5

Wenn Sie nur an 'z' interessiert sind, können Sie einen funktionsbasierten Index erstellen.

CREATE INDEX users_z_idx ON users (INSTR(last_name,'z')) 

Dann würde Ihre Abfrage WHERE INSTR(last_name,'z') > 0 verwenden.

Mit diesem Ansatz müssten Sie für jedes Zeichen, nach dem Sie suchen möchten, einen eigenen Index erstellen. Ich nehme an, wenn Sie das oft machen, lohnt es sich, für jeden Buchstaben einen Index zu erstellen.

Denken Sie auch daran, dass, wenn Ihre Daten die Namen standardmäßig groß geschrieben haben (zB "Zaxxon"), sowohl Ihr Beispiel als auch meins nicht mit Namen übereinstimmen, die mit einem Z beginnen durch Einfügen von LOWER in den Suchausdruck: INSTR(LOWER(last_name),'z').

+3

Noch effizienter wäre es, nur die Zeilen mit z ... CREATE INDEX users_z_idx ON Benutzer (Case wenn INSTR (last_name, 'z')> 0 dann 1 else null Ende)) –

+0

Guter Punkt, David. –

0

Bedenken Sie, dass es nur sinnvoll ist, etwas anderes als einen vollständigen Tabellenscan zu verwenden, um diese Werte zu finden, wenn die Anzahl der Blöcke, die eine zum Prädikat passende Zeile enthalten, wesentlich kleiner ist als die Gesamtzahl der Blöcke in der Tabelle. Aus diesem Grund lehnt Oracle bei der Verwendung von LIKE '% x%', bei der x eine sehr kleine Zeichenfolge ist, die Verwendung eines Indexes häufig ab, um einen vollständigen Scan durchzuführen. Wenn zum Beispiel der Optimierer glaubt, dass die Verwendung eines Index immer noch Einzelblock-Lesevorgänge bei (etwa) 20% der Tabellenblöcke erfordert, ist ein vollständiger Tabellenscan wahrscheinlich eine bessere Option als ein Index-Scan.

Manchmal wissen Sie, dass Ihr Prädikat viel selektiver ist, als der Optimierer abschätzen kann. In einem solchen Fall können Sie nach einem Optimierungshinweis suchen, um einen Index-Fast-Full-Scan für die relevante Spalte durchzuführen (insbesondere wenn der Index ein viel kleineres Segment als die Tabelle ist).

SELECT /*+ index_ffs(users (users.last_name)) */ 
     * 
FROM users 
WHERE last_name LIKE "%z%" 
3

Sie können es auf diese Weise tun INSTR mit:

SELECT * FROM users WHERE INSTR(LOWER(last_name), 'z') > 0; 

INSTR gibt Null zurück, wenn der Teil nicht in der Zeichenfolge ist.

Aus Interesse, warum willst du nicht wie verwenden?

Edit: Ich habe mir die Freiheit genommen, die Suche unsensibel zu machen, damit Sie Bob Zebidee nicht verpassen.:-)

Verwandte Themen