Ваш запит є майже оптимальним. Синтаксис не стане набагато коротшим, запит не стане набагато швидшим:
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індексуватися?