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 TO
für mich in beiden Fällen schnellere Ergebnisse als für .
Mit einem geeigneten B-Tree-Index LIKE
gewinnt 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 TO
Auch 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 TO
ist einfach sinnlos . Eine eigenartige Mischform von LIKE
und 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
/ ILIKE
pattern (und einfache Regexp-Muster mit ~
) mithilfe eines GIN- oder GiST-Index bereitzustellen.
Details, Beispiel und Links:
pg_trgm
bietet 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 TO
Ausdrücke werden intern in reguläre Ausdrücke umgeschrieben. Daher gibt es für jeden SIMILAR TO
Ausdruck 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 LIKE
sowieso schneller .
SIMILAR TO
wird 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 ANALYZE
offenbart 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 TO
wurde mit einem regulären Ausdruck ( ~
) umgeschrieben .
Ultimative Leistung für diesen speziellen Fall
Aber EXPLAIN ANALYZE
verrä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_ops
oder mit locale C
) einfach links verankerte Ausdrücke sind mit diesen Textmustern Operatoren neu geschrieben: ~>=~
, ~<=~
, ~>~
, ~<~
. Dies ist der Fall für ~
, ~~
oder SIMILAR TO
gleichermaßen.
Gleiches gilt für Indizes zu varchar
Typen mit varchar_pattern_ops
oder char
mit 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.name
indiziert?