Ваш запрос в значительной степени оптимальный. Синтаксис не станет намного короче, запрос не станет намного быстрее:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Если вы действительно хотите сократить синтаксис , используйте регулярное выражение с ветвями :
...
WHERE name ~ '^(B|D).*'
Или немного быстрее, с классом персонажа :
...
WHERE name ~ '^[BD].*'
Быстрый тест без индекса дает более быстрые результаты, чем SIMILAR TO
в любом случае для меня.
С соответствующим индексом B-Tree LIKE
выигрывает эту гонку на порядки.
Прочитайте основы сопоставления с образцом в руководстве .
Индекс для превосходной производительности
Если вас интересует производительность, создайте такой индекс для больших таблиц:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Делает такой запрос быстрее на порядок. Особые соображения применяются для порядка сортировки, зависящего от локали. Подробнее о классах операторов читайте в руководстве . Если вы используете стандартную локализацию "C" (большинство людей этого не делают), подойдет простой индекс (с классом оператора по умолчанию).
Такой индекс хорош только для левых якорных паттернов (совпадающих с начала строки).
SIMILAR TO
или регулярные выражения с базовыми левосторонними выражениями также могут использовать этот индекс. Но не с ветвями (B|D)
или классами символов [BD]
(по крайней мере, в моих тестах на PostgreSQL 9.0).
Для совпадения триграмм или текстового поиска используются специальные индексы GIN или GiST.
Обзор операторов сопоставления с образцом
LIKE
( ~~
) прост и быстр, но ограничен в своих возможностях.
ILIKE
( ~~*
) регистронезависимый вариант.
pg_trgm расширяет поддержку индекса для обоих.
~
(совпадение регулярного выражения) является мощным, но более сложным и может быть медленным для чего-то большего, чем базовые выражения.
SIMILAR TO
просто бессмысленно . Своеобразный полукровка LIKE
и регулярные выражения. Я никогда не использую это. Смотри ниже.
% - это оператор «сходства», предоставляемый дополнительным модулемpg_trgm
. Смотри ниже.
@@
является оператором текстового поиска. Смотри ниже.
pg_trgm - сопоставление триграмм
Начиная с PostgreSQL 9.1, вы можете упростить расширение, pg_trgm
чтобы обеспечить поддержку индексов для любого LIKE
/ ILIKE
шаблона (и простых шаблонов регулярных выражений с ~
) с использованием индекса GIN или GiST.
Подробности, пример и ссылки:
pg_trgm
также предоставляет следующие операторы :
%
- оператор "сходства"
<%
(commutator %>
:) - оператор "word_s Similarity" в Postgres 9.6 или более поздней версии
<<%
(commutator %>>
:) - оператор "strict_word_simility" в Postgres 11 или более поздней версии
Поиск текста
Это специальный тип сопоставления с шаблоном с отдельными типами инфраструктуры и индекса. Он использует словари и основы и является отличным инструментом для поиска слов в документах, особенно для естественных языков.
Сопоставление префиксов также поддерживается:
Так же как поиск фразы начиная с Postgres 9.6:
Рассмотрим введение в руководство и обзор операторов и функций .
Дополнительные инструменты для нечеткого соответствия строк
Дополнительный модуль fuzzystrmatch предлагает еще несколько опций, но производительность, как правило, уступает всем вышеперечисленным.
В частности, различные реализации levenshtein()
функции могут быть инструментальными.
Почему регулярные выражения ( ~
) всегда быстрее чем SIMILAR TO
?
Ответ прост. SIMILAR TO
выражения переписываются внутри регулярных выражений. Таким образом, для каждого SIMILAR TO
выражения есть хотя бы одно более быстрое регулярное выражение (которое позволяет сэкономить на переписывании выражения). Там нет прирост производительности при использовании SIMILAR TO
никогда .
А простые выражения, которые можно сделать с помощью LIKE
( ~~
), в LIKE
любом случае быстрее .
SIMILAR TO
поддерживается только в PostgreSQL, потому что он оказался в ранних версиях стандарта SQL. Они до сих пор не избавились от этого. Но есть планы удалить его и включить вместо него совпадения регулярных выражений - или я так слышал.
EXPLAIN ANALYZE
раскрывает это. Попробуйте сами с любым столом!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
раскрывает:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
был переписан с помощью регулярного выражения ( ~
).
Максимальная производительность в данном конкретном случае
Но EXPLAIN ANALYZE
раскрывает больше. Попробуйте, с указанным выше индексом:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
раскрывает:
...
-> 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))
Внутренне, с индексом , который не зависит от локали известно ( text_pattern_ops
или с помощью локали C
) простые выражения лево-якорь переписываются с этими операторами текста шаблона: ~>=~
, ~<=~
, ~>~
, ~<~
. Это случай ~
, ~~
или SIMILAR TO
как.
То же самое верно для индексов varchar
типов с varchar_pattern_ops
или char
с bpchar_pattern_ops
.
Итак, применительно к исходному вопросу, это самый быстрый способ :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Конечно, если вам придется искать соседние инициалы , вы можете упростить дальнейшее:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Выгода по сравнению с простым использованием ~
или ~~
крошечная. Если производительность не является вашим главным требованием, вам следует просто придерживаться стандартных операторов - прийти к тому, что у вас уже есть в вопросе.
s.name
индексироваться?