2010-12-01 5 views
0

Wir haben drei Tabellen unsere Produkte und Keywords zu halten:SQL-Schlüsselwort-Suchalgorithmus: Dieses SQL führt eine sequenzielle Suche aus, wie wird eine indizierte Suche durchgeführt?

Product {int ID, string name, ...} 
ProductKeyword {int productID, int keywordID} 
Keyword {int ID, string keyword} 

Dieser SQL-Code gibt die wichtigsten Produkte an die am wenigsten relevanten Produkte Schlüsselwörter wie die Benutzer Kriterien suchen zu müssen. searchWordTable ist eine Tabelle mit Suchbegriffen. @keywordCount ist eine Zählung der Suchbegriffe. Dadurch werden alle Produkte zurückgegeben, die ein oder mehrere Keywords enthalten, sortiert nach der Anzahl der Keywords, die für jedes Produkt gefunden wurden.

select productid, productname, count(*) * 1/@keywordCount as percentRelevant 
from (select keyword, productid, productname 
     from product 
      join productkeyword on ... 
      join keyword on ... 
      join searchWordTable on searchwordtable.keyword like 
        '%' + keyword.keyword + '%') K -- like join aweful 
group by productid, productname 
order by percentRelevant desc -- Most relevant first 

Das Problem ist, dass es eine sequenzielle Suche ist, die jedes Schlüsselwort vergleicht, das wir haben. Es ist nicht schlecht, aber Suchvorgänge können eine Minute mit einer Million Datensätze dauern.

Wie könnte ich die Abfrage neu schreiben, um like nicht zu verwenden, hoffentlich eine indexierte Suche verwenden und ähnliche Ergebnisse erhalten? Sie verwenden like, um teilweise Übereinstimmungen zu erhalten, z. B. "bone" in "knochenlos".

Links zu besseren SQL-Algorithmen würden sicherlich geschätzt werden.

+1

In Ihrem Beispiel ("bone" in "knochenlos") könnten Sie das erste "%" weglassen und - bang - ein Index kann verwendet werden. – AndreKR

+0

Das ist eine sehr gute Idee. Wenn wir unsere Keywords auf einzelne Wörter beschränken könnten, würde das ziemlich gut funktionieren. Wir haben ähnliche Keywords wie 'Kelloggs Corn Flakes'. –

Antwort

2

Wie Sie tötet, vor allem mit diesem führenden Platzhalter, der alle Indizes vollständig entfernt, die die Spalten haben können.

Sie sollten sich mit der Volltextindizierung von SQL Server beschäftigen. contains wird wahrscheinlich viel schneller und ist viel stärker für partielle Übereinstimmungen der Art, die Sie zu tun scheinen.

1

Nun könnten Sie einen Volltextindex für diese Spalte implementieren, der die Leistung von SELECT-Anweisungen unterstützt, aber die Leistung der anderen drei CRUD-Operationen beeinträchtigt, da der Index bei jeder Operation aktualisiert werden muss. Dann glaube ich, dass Sie ein CONTAINS oder ein anderes ähnliches Schlüsselwort verwenden würden. Hier ist noch mehr information.