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 TOw obu przypadkach dla mnie.
Przy odpowiednim indeksie B-Tree LIKEwygrywa 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 TOlub 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 TOjest po prostu bezcelowe . Osobliwa półrasa LIKEi 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_trgmaby 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_trgmzapewnia 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 TOwyrażenia są wewnętrznie przepisywane na wyrażenia regularne. Tak więc dla każdego SIMILAR TOwyraż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 LIKEtak szybsze .
SIMILAR TOjest 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 ANALYZEujawnia 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 TOzostał przepisany wyrażeniem regularnym ( ~).
Najwyższa wydajność w tym konkretnym przypadku
Ale EXPLAIN ANALYZEujawnia 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_opslub 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 TOpodobnie.
To samo dotyczy indeksów varchartypów z varchar_pattern_opslub charz 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.nameindeksowany?