Sua consulta é praticamente a ideal. A sintaxe não ficará muito mais curta, a consulta não ficará muito mais rápida:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Se você realmente deseja reduzir a sintaxe , use uma expressão regular com branches :
...
WHERE name ~ '^(B|D).*'
Ou um pouco mais rápido, com uma classe de personagem :
...
WHERE name ~ '^[BD].*'
Um teste rápido sem índice gera resultados mais rápidos do que SIMILAR TOem ambos os casos para mim.
Com um índice B-Tree apropriado, LIKEvence esta corrida por ordens de magnitude.
Leia o básico sobre correspondência de padrões no manual .
Índice para desempenho superior
Se você está preocupado com o desempenho, crie um índice como este para tabelas maiores:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Torna esse tipo de consulta mais rápido em ordens de magnitude. Considerações especiais se aplicam à ordem de classificação específica do código do idioma. Leia mais sobre classes de operadores no manual . Se você estiver usando o código de idioma "C" padrão (a maioria das pessoas não), um índice simples (com classe de operador padrão) será suficiente.
Esse índice é bom apenas para padrões ancorados à esquerda (correspondendo desde o início da string).
SIMILAR TOou expressões regulares com expressões ancoradas à esquerda básicas também podem usar esse índice. Mas não com ramos (B|D)ou classes de caracteres [BD](pelo menos nos meus testes no PostgreSQL 9.0).
As correspondências de trigrama ou a pesquisa de texto usam índices especiais GIN ou GiST.
Visão geral dos operadores de correspondência de padrões
LIKE( ~~) é simples e rápido, mas limitado em suas capacidades.
ILIKE( ~~*) a variante que não diferencia maiúsculas de minúsculas.
pg_trgm estende o suporte ao índice para ambos.
~ (correspondência de expressão regular) é poderoso, mas mais complexo e pode ser lento para algo além de expressões básicas.
SIMILAR TOé apenas inútil . Um mestiço peculiar LIKEe expressões regulares. Eu nunca uso isso. Ver abaixo.
% é o operador "similaridade", fornecido pelo módulo adicionalpg_trgm. Ver abaixo.
@@é o operador de pesquisa de texto. Ver abaixo.
pg_trgm - correspondência de trigrama
A partir do PostgreSQL 9.1, você pode facilitar a extensão pg_trgmpara fornecer suporte ao índice para qualquer padrão LIKE/ ILIKE(e padrões simples de regexp ~) usando um índice GIN ou GiST.
Detalhes, exemplo e links:
pg_trgmtambém fornece esses operadores :
% - o operador "similaridade"
<%(comutador %>:) - o operador "word_similarity" no Postgres 9.6 ou posterior
<<%(comutador %>>:) - o operador "strict_word_similarity" no Postgres 11 ou posterior
Pesquisa de texto
É um tipo especial de correspondência de padrões com tipos de infraestrutura e índice separados. Ele usa dicionários e stemming e é uma ótima ferramenta para encontrar palavras em documentos, especialmente para idiomas naturais.
A correspondência de prefixo também é suportada:
Assim como a pesquisa de frases desde o Postgres 9.6:
Considere a introdução no manual e a visão geral dos operadores e funções .
Ferramentas adicionais para correspondência de seqüência difusa
O módulo adicional fuzzystrmatch oferece mais algumas opções, mas o desempenho geralmente é inferior a todos os itens acima.
Em particular, várias implementações da levenshtein()função podem ser instrumentais.
Por que as expressões regulares ( ~) são sempre mais rápidas que SIMILAR TO?
A resposta é simples. SIMILAR TOexpressões são reescritas em expressões regulares internamente. Portanto, para cada SIMILAR TOexpressão, há pelo menos uma expressão regular mais rápida (que economiza a sobrecarga de reescrever a expressão). Não há ganho de desempenho ao usar SIMILAR TO sempre .
E expressões simples que podem ser feitas com LIKE( ~~) são mais rápidas de LIKEqualquer maneira.
SIMILAR TOsó é suportado no PostgreSQL porque acabou nos primeiros rascunhos do padrão SQL. Eles ainda não se livraram disso. Mas há planos para removê-lo e incluir correspondências regexp - ou pelo menos ouvi dizer.
EXPLAIN ANALYZErevela isso. Apenas tente com qualquer mesa!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Revela:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TOfoi reescrito com uma expressão regular ( ~).
Melhor desempenho para este caso em particular
Mas EXPLAIN ANALYZErevela mais. Tente, com o índice mencionado anteriormente:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Revela:
...
-> 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))
Internamente, com um índice que não está locale-aware ( text_pattern_opsou usando local C) expressões simples ancorado-esquerda são reescritas com estes operadores padrão de texto: ~>=~, ~<=~, ~>~, ~<~. Este é o caso ~, ~~ou SIMILAR TOsimilar.
O mesmo vale para índices em varchartipos com varchar_pattern_opsou charcom bpchar_pattern_ops.
Portanto, aplicada à pergunta original, esta é a maneira mais rápida possível :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Obviamente, se você procurar iniciais adjacentes , poderá simplificar ainda mais:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
O ganho sobre o uso simples de ~ou ~~é pequeno. Se o desempenho não for seu requisito primordial, você deve apenas manter-se com os operadores padrão - chegando ao que você já tem na pergunta.
s.nameindexado?