Besserer Ansatz für "WIE ODER WIE, ODER WIE ODER WIE ODER WIE"

10

In dieser Frage hat er das gleiche Problem wie ich. Ich brauche so etwas wie:

select * from blablabla 
where product 
like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%' 

Dies ist hässlich und verwendet keine Indizes. In diesem Fall ist dies wirklich die einzige Möglichkeit, dies zu tun (um mehrere Wörter innerhalb einer Zeichenfolge auszuwählen), oder sollte ich FULLTEXT verwenden?

Soweit ich weiß, kann ich mit Volltext mehrere Wörter innerhalb einer Zeichenfolge auswählen.

Diese Frage bezieht sich auch auf Volltext

Racer SQL
quelle
3
Was ist der Datentyp der Produktspalte? Wie viele Zeichen durchschnittlich?
Joe Obbish

Antworten:

17

Volltextindizes sind im Allgemeinen kein Wundermittel und erfordern zusätzliche Wartung, Speicherplatz und ziemlich aufdringliche Änderungen an Abfragemustern.

Wenn Sie nicht wirklich große Dokumente indizieren müssen (denken Sie an E-Mail-Textkörper, PDFs, Word-Dokumente usw.), sind sie übertrieben (und wenn wir ehrlich sind, würde ich diesen Prozess vollständig und vollständig aus SQL Server entfernen benutze Elasticsearch oder ähnliches).

Für kleinere Anwendungsfälle sind berechnete Spalten im Allgemeinen ein besserer Ansatz.

Hier ist eine kurze Demo-Einrichtung:

use tempdb

CREATE TABLE #fulltextindexesarestupid (Id INT PRIMARY KEY CLUSTERED, StopAbusingFeatures VARCHAR(100))

INSERT #fulltextindexesarestupid (Id)
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY (@@ROWCOUNT))
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2

UPDATE #fulltextindexesarestupid
SET StopAbusingFeatures = CASE WHEN Id % 15 = 0 THEN 'Bad'
                               WHEN Id % 3 = 0 THEN 'Idea'
                               WHEN Id % 5 = 0 THEN 'Jeans'
                               END


ALTER TABLE #fulltextindexesarestupid 
ADD LessBad AS CONVERT(BIT, CASE WHEN StopAbusingFeatures LIKE '%Bad%' THEN 1
                    WHEN StopAbusingFeatures LIKE '%Idea%' THEN 1
                    ELSE 0 END)

CREATE UNIQUE NONCLUSTERED INDEX ix_whatever ON #fulltextindexesarestupid (LessBad, Id)

Abfragen, die sogar auf einer nicht persistenten Spalte basieren, geben uns einen Plan, der 'Indizes' und alles verwendet :)

SELECT COUNT(*)
FROM #fulltextindexesarestupid AS f
WHERE LessBad = 1

NÜSSE

Erik Darling
quelle
-3

Die Antwort von sp_BlitzErik trifft auf viele gute Punkte, aber ich denke nicht, dass Sie deshalb die Volltextsuche nicht verwenden sollten. Die Volltextsuche ist nicht dazu da, das zu tun, was Sie denken. Es ist nicht da, um mehrere Felder zu durchsuchen. Es dient dazu, Wortinhalte zu vektorisieren und Wörterbücher, Stubbing, Lexer, Gazetteer, die Beseitigung von Stoppwörtern und eine Reihe anderer Tricks zu verwenden, von denen keiner zutrifft. Oder es wurde noch nicht nachgewiesen, dass sie zutreffen.

Ich bin auch nicht mit der Lösung einverstanden, obwohl ich nicht sicher bin, wie ich dies in SQL Server besser machen kann. Lassen Sie uns seine Daten für PostgreSQL neu erstellen - es ist viel sauberer, sie auch in PostgreSQL zu erstellen.

CREATE TABLE fulltextindexesarestupid
AS
  SELECT
    id,
    CASE WHEN Id % 15 = 0 THEN 'Bad'
      WHEN Id % 3 = 0 THEN 'Idea'
      WHEN Id % 5 = 0 THEN 'Jeans'
    END AS StopAbusingFeatures
  FROM generate_series(1,1000000) AS id;

Was Sie jetzt wollen, ist ein Aufzählungstyp,

CREATE TYPE foo AS ENUM ('Bad', 'Idea', 'Jeans');

ALTER TABLE fulltextindexesarestupid
  ALTER StopAbusingFeatures
  SET DATA TYPE foo
  USING StopAbusingFeatures::foo;

Jetzt haben Sie die Zeichenfolgen zu ganzzahligen Darstellungen reduziert. Aber noch besser können Sie sie wie zuvor abfragen.

SELECT *
FROM fulltextindexesarestupid
WHERE StopAbusingFeatures = 'Bad';

Dies hat den Effekt.

  1. verbirgt die Tatsache, dass Ihre Kategorien ein Aufzählungstyp sind. Diese Komplexität ist im Typ enthalten und für den Benutzer verborgen.
  2. Außerdem wird die Wartung für diese Kategorien auf den Typ gesetzt.
  3. es ist standardisiert.
  4. Die Zeilengröße wird nicht vergrößert.

Ohne diese Vorteile versuchen Sie im Wesentlichen nur, den Zeichenfolgenvergleich zu optimieren. Aber leider bin ich mir nicht einmal sicher, wie sp_BlitzErik zu der Antwort kommt, wenn der Code im Vorschlag angegeben ist.

like '%rock%' or
like '%paper%' or
like '%scisor%' or
like '%car%' or
like '%pasta%'

Sie können die Token mithilfe einer Aufzählung oder der von sp_BlitzErik vorgeschlagenen Hand-Rolling-Methode auf Ganzzahlen reduzieren, aber wenn Sie das Reduzieren durchführen können, warum machen Sie das auch nicht verankert? Dh wenn Sie wissen, dass '% pasta%' das Zeichen 'Pasta' ist, warum haben Sie das %auf beiden Seiten? Ohne '%' ist dies eine Gleichheitsprüfung und sollte auch als Text ziemlich schnell sein.

Evan Carroll
quelle