Ihre Anfrage ist so ziemlich das Optimum. Die Syntax wird nicht viel kürzer, die Abfrage wird nicht viel schneller:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Wenn Sie die Syntax wirklich verkürzen möchten , verwenden Sie einen regulären Ausdruck mit Verzweigungen :
...
WHERE name ~ '^(B|D).*'
Oder etwas schneller mit einer Charakterklasse :
...
WHERE name ~ '^[BD].*'
Ein schneller Test ohne Index liefert SIMILAR TOfür mich in beiden Fällen schnellere Ergebnisse als für .
Mit einem geeigneten B-Tree-Index LIKEgewinnt dieses Rennen um Größenordnungen.
Lesen Sie die Grundlagen zum Pattern Matching im Handbuch .
Index für überlegene Leistung
Wenn Sie sich mit der Leistung befassen, erstellen Sie einen Index für größere Tabellen:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Beschleunigt diese Art der Abfrage um Größenordnungen. Besondere Überlegungen gelten für die länderspezifische Sortierreihenfolge. Weitere Informationen zu Operator-Klassen finden Sie im Handbuch . Wenn Sie das Standardgebietsschema "C" verwenden (die meisten Benutzer tun dies nicht), reicht ein einfacher Index (mit Standardoperatorklasse) aus.
Ein solcher Index eignet sich nur für links verankerte Muster (Abgleich ab dem Anfang der Zeichenfolge).
SIMILAR TOAuch reguläre Ausdrücke mit einfachen links verankerten Ausdrücken können diesen Index verwenden. Aber nicht mit Zweigen (B|D)oder Zeichenklassen [BD](zumindest in meinen Tests unter PostgreSQL 9.0).
Trigramm-Übereinstimmungen oder Textsuche verwenden spezielle GIN- oder GiST-Indizes.
Übersicht der Mustervergleichsoperatoren
LIKE( ~~) ist einfach und schnell, aber in seinen Fähigkeiten begrenzt.
ILIKE( ~~*) die case insensitive Variante.
pg_trgm erweitert die Indexunterstützung für beide.
~ (Übereinstimmung mit regulären Ausdrücken) ist leistungsfähig, aber komplexer und kann für mehr als nur grundlegende Ausdrücke langsam sein.
SIMILAR TOist einfach sinnlos . Eine eigenartige Mischform von LIKEund regulären Ausdrücken. Ich benutze es nie. Siehe unten.
% ist der "Ähnlichkeits" -Operator, der vom Zusatzmodul bereitgestellt wirdpg_trgm. Siehe unten.
@@ist der Textsuchoperator. Siehe unten.
pg_trgm - Trigrammabgleich
Ab PostgreSQL 9.1 können Sie die Erweiterung vereinfachen pg_trgm, um Indexunterstützung für any LIKE / ILIKEpattern (und einfache Regexp-Muster mit ~) mithilfe eines GIN- oder GiST-Index bereitzustellen.
Details, Beispiel und Links:
pg_trgmbietet auch diese Operatoren :
% - der Operator "Ähnlichkeit"
<%(Kommutator %>:) - Der Operator "word_similarity" in Postgres 9.6 oder höher
<<%(Kommutator %>>:) - Der Operator "strict_word_similarity" in Postgres 11 oder höher
Textsuche
Ist eine spezielle Art des Mustervergleichs mit separaten Infrastruktur- und Indextypen. Es verwendet Wörterbücher und Stemming und ist ein großartiges Werkzeug, um Wörter in Dokumenten zu finden, insbesondere für natürliche Sprachen.
Der Präfixabgleich wird ebenfalls unterstützt:
Sowie die Phrasensuche seit Postgres 9.6:
Beachten Sie die Einführung im Handbuch und die Übersicht der Bediener und Funktionen .
Zusätzliche Tools für den Fuzzy-String-Abgleich
Das Zusatzmodul fuzzystrmatch bietet einige weitere Optionen, die Leistung ist jedoch generell schlechter als die oben genannten.
Insbesondere können verschiedene Implementierungen der levenshtein()Funktion hilfreich sein.
Warum sind reguläre Ausdrücke ( ~) immer schneller als SIMILAR TO?
Die Antwort ist einfach. SIMILAR TOAusdrücke werden intern in reguläre Ausdrücke umgeschrieben. Daher gibt es für jeden SIMILAR TOAusdruck mindestens einen schnelleren regulären Ausdruck (der den Aufwand für das Neuschreiben des Ausdrucks erspart). Es gibt keinen Leistungsgewinn bei der Verwendung SIMILAR TO jemals .
Und einfache Ausdrücke, die mit LIKE( ~~) gemacht werden können, sind LIKEsowieso schneller .
SIMILAR TOwird nur in PostgreSQL unterstützt, weil es zu frühen Entwürfen des SQL-Standards geführt hat. Sie haben es immer noch nicht losgeworden. Aber es gibt Pläne, es zu entfernen und stattdessen reguläre Ausdrücke einzuschließen - oder wie ich gehört habe.
EXPLAIN ANALYZEoffenbart es. Probieren Sie es einfach mit einem Tisch aus!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Enthüllt:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TOwurde mit einem regulären Ausdruck ( ~) umgeschrieben .
Ultimative Leistung für diesen speziellen Fall
Aber EXPLAIN ANALYZEverrät mehr. Versuchen Sie es mit dem oben genannten Index:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Enthüllt:
...
-> Bitmap Heap Scan on spelers (cost= ...
Filter: (name ~ '^B.*'::text)
-> Bitmap Index Scan on spelers_name_text_pattern_ops_idx (cost= ...
Index Cond: ((prod ~>=~ 'B'::text) AND (prod ~<~ 'C'::text))
Intern mit einem Index, der nicht locale-aware (wird text_pattern_opsoder mit locale C) einfach links verankerte Ausdrücke sind mit diesen Textmustern Operatoren neu geschrieben: ~>=~, ~<=~, ~>~, ~<~. Dies ist der Fall für ~, ~~oder SIMILAR TOgleichermaßen.
Gleiches gilt für Indizes zu varcharTypen mit varchar_pattern_opsoder charmit bpchar_pattern_ops.
Auf die ursprüngliche Frage angewendet ist dies der schnellste Weg :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Sollten Sie einmal nach benachbarten Initialen suchen , können Sie dies natürlich weiter vereinfachen:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Der Gewinn gegenüber dem normalen Gebrauch von ~oder ~~ist winzig. Wenn Leistung nicht Ihre oberste Anforderung ist, sollten Sie sich einfach an die Standardoperatoren halten und zu dem gelangen, was Sie bereits in der Frage haben.
s.nameindiziert?