Su consulta es más o menos la óptima. La sintaxis no será mucho más corta, la consulta no será mucho más rápida:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Si realmente quiere acortar la sintaxis , use una expresión regular con ramas :
...
WHERE name ~ '^(B|D).*'
O un poco más rápido, con una clase de personaje :
...
WHERE name ~ '^[BD].*'
Una prueba rápida sin índice produce resultados más rápidos que SIMILAR TO
en cualquier caso para mí.
Con un índice B-Tree apropiado, LIKE
gana esta carrera por orden de magnitud.
Lea los conceptos básicos sobre la coincidencia de patrones en el manual .
Índice para un rendimiento superior
Si le preocupa el rendimiento, cree un índice como este para tablas más grandes:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Hace este tipo de consulta más rápido por orden de magnitud. Se aplican consideraciones especiales para el orden de clasificación específico de la localidad. Lea más sobre las clases de operador en el manual . Si está utilizando la configuración regional "C" estándar (la mayoría de la gente no lo hace), un índice simple (con la clase de operador predeterminada) servirá.
Tal índice solo es bueno para patrones anclados a la izquierda (coincidencia desde el inicio de la cadena).
SIMILAR TO
o expresiones regulares con expresiones básicas ancladas a la izquierda también pueden usar este índice. Pero no con ramas (B|D)
o clases de caracteres [BD]
(al menos en mis pruebas en PostgreSQL 9.0).
Las coincidencias de trigrama o la búsqueda de texto utilizan índices especiales GIN o GiST.
Descripción general de los operadores de coincidencia de patrones
LIKE
( ~~
) es simple y rápido pero limitado en sus capacidades.
ILIKE
( ~~*
) la variante insensible a mayúsculas y minúsculas.
pg_trgm extiende el soporte de índice para ambos.
~
(coincidencia de expresión regular) es potente pero más complejo y puede ser lento para cualquier cosa más que expresiones básicas.
SIMILAR TO
simplemente no tiene sentido . Un mestizo peculiar de LIKE
y expresiones regulares. Nunca lo uso Vea abajo.
% es el operador de "similitud", proporcionado por el módulo adicionalpg_trgm
. Vea abajo.
@@
es el operador de búsqueda de texto. Vea abajo.
pg_trgm - coincidencia de trigram
Comenzando con PostgreSQL 9.1 , puede facilitar la extensión pg_trgm
para proporcionar soporte de índice para cualquier LIKE
/ ILIKE
patrón (y patrones de expresión regular simples con ~
) usando un índice GIN o GiST.
Detalles, ejemplo y enlaces:
pg_trgm
También proporciona estos operadores :
%
- el operador de "similitud"
<%
(conmutador %>
:) - el operador "word_similarity" en Postgres 9.6 o posterior
<<%
(conmutador %>>
:) - el operador "estricta_palabra_similaridad" en Postgres 11 o posterior
Búsqueda de texto
Es un tipo especial de coincidencia de patrones con infraestructura separada y tipos de índice. Utiliza diccionarios y derivaciones y es una gran herramienta para encontrar palabras en documentos, especialmente para idiomas naturales.
La coincidencia de prefijos también es compatible:
Además de la búsqueda de frases desde Postgres 9.6:
Considere la introducción en el manual y el resumen de operadores y funciones .
Herramientas adicionales para la coincidencia de cadenas difusas
El módulo adicional fuzzystrmatch ofrece algunas opciones más, pero el rendimiento generalmente es inferior a todo lo anterior.
En particular, diversas implementaciones de la levenshtein()
función pueden ser instrumentales.
¿Por qué las expresiones regulares ( ~
) siempre son más rápidas que SIMILAR TO
?
La respuesta es simple. SIMILAR TO
Las expresiones se reescriben en expresiones regulares internamente. Entonces, para cada SIMILAR TO
expresión, hay al menos una expresión regular más rápida (que ahorra la sobrecarga de reescribir la expresión). No hay ganancia de rendimiento al usar SIMILAR TO
nunca .
Y las expresiones simples que se pueden hacer con LIKE
( ~~
) son más rápidas con de LIKE
todos modos.
SIMILAR TO
solo es compatible con PostgreSQL porque terminó en los primeros borradores del estándar SQL. Todavía no se han librado de eso. Pero hay planes para eliminarlo e incluir coincidencias regexp, o eso escuché.
EXPLAIN ANALYZE
lo revela ¡Intenta con cualquier mesa tú mismo!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Revela:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
ha sido reescrito con una expresión regular ( ~
).
Máximo rendimiento para este caso particular
Pero EXPLAIN ANALYZE
revela más. Pruebe, con el índice mencionado anteriormente en su lugar:
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, con un índice que no está al tanto de la configuración regional ( text_pattern_ops
o el uso de la configuración regional C
) simples expresiones de izquierda-anclado se reescriben con estos operadores patrón de texto: ~>=~
, ~<=~
, ~>~
, ~<~
. Este es el caso para ~
, ~~
o SIMILAR TO
por igual.
Lo mismo es cierto para los índices en varchar
tipos con varchar_pattern_ops
o char
con bpchar_pattern_ops
.
Entonces, aplicado a la pregunta original, esta es la forma más rápida posible :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Por supuesto, si por casualidad busca iniciales adyacentes , puede simplificar aún más:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
La ganancia sobre el uso simple de ~
o ~~
es pequeña. Si el rendimiento no es su requisito primordial, debe seguir con los operadores estándar, llegando a lo que ya tiene en la pregunta.
s.name
indexado?