MSSQL/T-SQL: alternative zu LIKE '%abc%'

Der MySQL Datenbank-Server für Internet- und Intranet-Lösungen.

MSSQL/T-SQL: alternative zu LIKE '%abc%'

Beitragvon max_payne » Di 26 Aug, 2008 18:03

hallo!
ich suche eine alternative zu dem oben genannten Like. grund: performance

ich habe es bereits mit dem volltextindex versucht, allerdings geht das nur wortweise.
dh: bei text "dies ist abc" kann man nach dies, ist, abc suchen, jedoch nicht nach "ab" oder "ies"

kennt jemand eine lösung?
max_payne
Ultimate Power-User
Ultimate Power-User
 
Beiträge: 4982
Registriert: Mo 30 Aug, 2004 12:25

Beitragvon wagsoul » Mi 27 Aug, 2008 07:56

Hast du das schon gelesen?

http://dev.mysql.com/doc/refman/5.1/de/ ... earch.html

Um so einen Volltext-Index wirklich zu nutzen, muss man mit anderen Kriterien als 'like' in der Abfrage suchen.

Kommen in deiner Where-Bedingung noch andere Spalten als die mit dem zu suchenden Text vor, oder machst du vielleicht sogar einen Join? Wenn ja, könnte man da auch noch viel optimieren.

Über jede Spalte die in der Where-Klausel vorkommt, kannst du einen Index legen, und für jeden Join einen Index über den Primärschlüssel der einen Tabelle und dem Fremdschlüssel in der anderen.
wagsoul
Profi-User
Profi-User
 
Beiträge: 1638
Registriert: Fr 04 Mai, 2007 20:53

Beitragvon wagsoul » Mi 27 Aug, 2008 08:42

Oder eine Möglichkeit gibt es wohl doch, die Suche (wahnsinnig) effizient zu machen.

Und zwar, indem man Informationen teilweise redundant speichert.


Ich nehme hier mal an, dass diese "Tabelle1" deine ist, die die Spalte mit dem zu suchenden Text beinhaltet.

Sie sieht spaltenmäßig so aus:
id,
spalte1,
psalte2,
spalte3,
...
textspalte

Die Spalte "textspalte" ist dabei jene, die deinen Text enthält.

Sagen wir, in dieser Tabelle ist folgende Zeile:

1, 4, 6, 3, ...., 'Das ist ein Test-Text'

Nun nehmen wir an, du willst nach allen Zeilen suchen, die in der Spalte textspalte das Wort "ist" enthalten. Dabei wirst du meine obige Zeile (+ andere vorhandene) erhalten.


Das könnte man mit einer zusätzlichen Tabelle realisieren, die so aussieht:
create table suchtabelle
id number(19) primary key,
tabelle1Id references tabelle1(id),
wort varchar2(1024) not null


Mit dieser 2. Tabelle machst du nichts Anderes, als dasss du dafür sorgst, dass sämtlicher Text dort auch eingetragen ist - allerdings unterteilt auf 1 Wort pro Tabellenzeile.

In unserem Beispiel würde für den oben beschriebenen Eintrag aus Tabelle1 Folgendes in der 2. Tabelle stehen:

1, 1, 'Das'
2, 1, 'ist'
3, 1, 'ein'
4, 1, 'Test-Text'


Willst du nun nach Zeilen der Tabelle1 suchen, die das Wort 'ist' in der Textspalte enthalten, so machst du das so:

select * from Tabelle1 where id in (

select distinct tabelle1Id from suchtabelle where LENGTH(wort) >= LENGTH('ist') and wort like '%ist%'

)

Vielleicht hilft das ja. Falls nicht, könntest du versuchen den Inhalt der 2. Tabelle so zu ändern, dass dieser nicht nur ganze Worte, sondern auch Wortfetzen enthält. Dann kannst du nämlich auf das % am Anfang in der Like-Klausel verzichten, womit dann ein Index genutzt wird, denn du dann natürlich über die Wort-Spalte legen musst.

Ist ein %-Zeichen am Anfang eines like-Arguments, werden nämlich keine Indizes benutzt.
wagsoul
Profi-User
Profi-User
 
Beiträge: 1638
Registriert: Fr 04 Mai, 2007 20:53

Beitragvon wagsoul » Mi 27 Aug, 2008 09:08

Als Endergebnis würde das dann so aussehen:

create index idx_suchtabelle_wort on suchtabelle(wort);

Wegen des Satzes "Das ist ein Test-Text" würde das drinnen stehen:

1, 1, 'Das ist ei'
2, 1, 'as ist ein'
3, 1, 's ist ein '
4, 1, ' ist ein T'
5, 1, 'ist ein Te'
6, 1, 'st ein Tes'
7, 1, 't ein Test'
8, 1, ' ein Test-'
9, 1, 'ein Test-T'
10, 1,' in Test-Te'
11, 1,' n Test-Tex'
12, 1,' Test-Text'
13, 1,' est-Text'
14, 1,' st-Text'
15, 1,' t-Text'
16, 1,' -Text'
17, 1,' Text'
18, 1,' ext'

Und der Select wäre so:

select * from Tabelle1 where id in (

select distinct tabelle1Id from suchtabelle where wort like concat(substring('ist', 0, 10), '%')

)

and textspalte like '%ist%';


Hier hat man sodann im Hauptselect erst wieder ein langsames like '%ist%', das ist aber notwendig, da der innere Select nur für Suchwörter mit max. 10 Zeichen funktioniert, und bei längeren Suchwörtern eventuell zu viele Ergebnisse liefert.

Andererseits sollte dieser innere Select trotzdem so gut filtern, dass der Rechenaufwand für das äußere langsame Like gegen "nicht notwendig" gehen sollte.


Auch wenn meine in der vorherigen Antwort präsentierte Lösung vielleicht nicht ganz optimal ist, sollte man hiermit das Problem nun wirklich endgültig erschlagen.

Es ist halt eine Frage des Festplattenspeichers, den man für diese Suchoptimierung bereit ist zu verwenden, und auch wie gut so eine MySQL-Datenbank mit Datenmengen im GB-Bereich umgehen kann, falls sich eine entsprechende Menge ergeben sollte.


--edit:
Wieso ich solche Beiträge hier scheibe, weiß ich selber nicht. Woanders würde man damit gutes Geld verdienen ;-)
wagsoul
Profi-User
Profi-User
 
Beiträge: 1638
Registriert: Fr 04 Mai, 2007 20:53

Beitragvon max_payne » Mi 27 Aug, 2008 20:30

Wieso ich solche Beiträge hier scheibe, weiß ich selber nicht. Woanders würde man damit gutes Geld verdienen

hui, dann sag ich mal danke!

ich werd mir das morgen gleich in der früh anschaun und umsetzen ;-)
max_payne
Ultimate Power-User
Ultimate Power-User
 
Beiträge: 4982
Registriert: Mo 30 Aug, 2004 12:25


Zurück zu MySQL

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 14 Gäste