Ваш запит є майже оптимальним. Синтаксис не стане набагато коротшим, запит не стане набагато швидшим:
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
також надає цих операторів :
%
- оператор "подібності"
<%
(комутатор %>
:) - оператор "word_s similarity" в Postgres 9.6 або пізнішої версії
<<%
(комутатор %>>
:) - оператор "строгого___подібності" в Постгресі 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
індексуватися?