Twoje zapytanie jest w zasadzie optymalne. Składnia nie będzie znacznie krótsza, zapytanie nie będzie znacznie szybsze:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Jeśli naprawdę chcesz skrócić składnię , użyj wyrażenia regularnego z rozgałęzieniami :
...
WHERE name ~ '^(B|D).*'
Lub nieco szybciej, z klasą postaci :
...
WHERE name ~ '^[BD].*'
Szybki test bez indeksu daje szybsze wyniki niż SIMILAR TO
w obu przypadkach dla mnie.
Przy odpowiednim indeksie B-Tree LIKE
wygrywa ten wyścig o rzędy wielkości.
Przeczytaj podstawowe informacje na temat dopasowywania wzorów w instrukcji .
Indeks doskonałej wydajności
Jeśli martwisz się wydajnością, utwórz taki indeks dla większych tabel:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Przyspiesza tego rodzaju zapytania o rzędy wielkości. Szczególne uwagi dotyczą kolejności sortowania specyficznej dla danego regionu. Przeczytaj więcej o klasach operatorów w instrukcji . Jeśli używasz standardowych ustawień regionalnych „C” (większość ludzi tego nie robi), zrobi to zwykły indeks (z domyślną klasą operatora).
Taki indeks jest dobry tylko dla wzorców zakotwiczonych w lewo (dopasowanie od początku łańcucha).
SIMILAR TO
lub wyrażenia regularne z podstawowymi wyrażeniami zakotwiczonymi w lewo również mogą korzystać z tego indeksu. Ale nie z gałęziami (B|D)
lub klasami znaków [BD]
(przynajmniej w moich testach na PostgreSQL 9.0).
Dopasowania Trigram lub wyszukiwanie tekstu używają specjalnych indeksów GIN lub GiST.
Przegląd operatorów dopasowywania wzorców
LIKE
( ~~
) jest prosty i szybki, ale ma ograniczone możliwości.
ILIKE
( ~~*
) wariant bez rozróżniania wielkości liter.
pg_trgm rozszerza obsługę indeksu dla obu.
~
(dopasowanie wyrażeń regularnych) jest potężne, ale bardziej złożone i może być powolne w przypadku czegoś więcej niż wyrażeń podstawowych.
SIMILAR TO
jest po prostu bezcelowe . Osobliwa półrasa LIKE
i wyrażenia regularne. Nigdy tego nie używam. Patrz poniżej.
% jest operatorem „podobieństwa” zapewnianym przez dodatkowy modułpg_trgm
. Patrz poniżej.
@@
jest operatorem wyszukiwania tekstu. Patrz poniżej.
pg_trgm - dopasowanie trygramu
Począwszy od PostgreSQL 9.1 możesz ułatwić rozszerzenie, pg_trgm
aby zapewnić obsługę indeksu dla dowolnego wzorca LIKE
/ ILIKE
(i prostych wzorców ~
wyrażeń regularnych z ) za pomocą indeksu GIN lub GiST.
Szczegóły, przykład i linki:
pg_trgm
zapewnia również tych operatorów :
%
- operator „podobieństwa”
<%
(komutator %>
:) - operator „word_similarity” w Postgresie 9.6 lub nowszym
<<%
(komutator %>>
:) - operator „strict_word_similarity” w Postgres 11 lub nowszy
Wyszukiwanie tekstu
Jest specjalnym rodzajem dopasowania wzorca z osobnymi typami infrastruktury i indeksu. Korzysta ze słowników i wyszukiwania oraz jest doskonałym narzędziem do wyszukiwania słów w dokumentach, szczególnie w przypadku języków naturalnych.
Obsługiwane jest również dopasowanie prefiksu :
Jak również wyszukiwanie fraz od Postgres 9.6:
Rozważ wprowadzenie w podręczniku oraz przegląd operatorów i funkcji .
Dodatkowe narzędzia do dopasowywania rozmytych ciągów znaków
Dodatkowy moduł fuzzystrmatch oferuje kilka dodatkowych opcji, ale wydajność jest ogólnie gorsza od wszystkich powyższych.
W szczególności różne implementacje levenshtein()
funkcji mogą być instrumentalne.
Dlaczego wyrażenia regularne ( ~
) są zawsze szybsze niż SIMILAR TO
?
Odpowiedź jest prosta. SIMILAR TO
wyrażenia są wewnętrznie przepisywane na wyrażenia regularne. Tak więc dla każdego SIMILAR TO
wyrażenia istnieje co najmniej jedno szybsze wyrażenie regularne (co pozwala zaoszczędzić koszty przepisywania wyrażenia). SIMILAR TO
Nigdy nie zyskujesz na wydajności .
A proste wyrażenia, które można wykonać za pomocą LIKE
( ~~
), są i LIKE
tak szybsze .
SIMILAR TO
jest obsługiwany tylko w PostgreSQL, ponieważ skończył we wczesnych wersjach językowych standardu SQL. Nadal się tego nie pozbyli. Ale są plany, aby go usunąć i dołączyć dopasowania wyrażeń regularnych - a przynajmniej tak słyszałem.
EXPLAIN ANALYZE
ujawnia to. Po prostu spróbuj sam z dowolnym stołem!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Ujawnia:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
został przepisany wyrażeniem regularnym ( ~
).
Najwyższa wydajność w tym konkretnym przypadku
Ale EXPLAIN ANALYZE
ujawnia więcej. Spróbuj, korzystając z wyżej wymienionego indeksu:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Ujawnia:
...
-> 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))
Wewnętrznie, z indeksem, który nie jest świadomy Locale ( text_pattern_ops
lub przy użyciu locale C
) proste wyrażenia lewe zakotwiczone są przepisywane z tych operatorów wzór tekst: ~>=~
, ~<=~
, ~>~
, ~<~
. Tak jest w przypadku ~
, ~~
lub SIMILAR TO
podobnie.
To samo dotyczy indeksów varchar
typów z varchar_pattern_ops
lub char
z bpchar_pattern_ops
.
Tak więc, zastosowany do pierwotnego pytania, jest to najszybszy możliwy sposób :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Oczywiście, jeśli zdarzy ci się szukać sąsiednich inicjałów , możesz uprościć dalej:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Zysk w porównaniu do zwykłego użycia ~
lub ~~
jest niewielki. Jeśli wydajność nie jest twoim najważniejszym wymogiem, powinieneś po prostu trzymać się standardowych operatorów - osiągając to, co już masz w pytaniu.
s.name
indeksowany?