Votre requête est à peu près l'optimum. La syntaxe ne sera pas beaucoup plus courte, la requête ne sera pas beaucoup plus rapide:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Si vous voulez vraiment raccourcir la syntaxe , utilisez une expression régulière avec des branches :
...
WHERE name ~ '^(B|D).*'
Ou légèrement plus vite, avec une classe de personnage :
...
WHERE name ~ '^[BD].*'
Un test rapide sans index donne des résultats plus rapides que SIMILAR TO
dans les deux cas pour moi.
Avec un index B-Tree approprié en place, LIKE
remporte cette course par ordre de grandeur.
Lisez les bases sur la correspondance des modèles dans le manuel .
Indice pour une performance supérieure
Si les performances vous préoccupent, créez un index comme celui-ci pour les tables plus volumineuses:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Rend ce genre de requête plus rapidement par ordre de grandeur. Des considérations spéciales s'appliquent à l'ordre de tri spécifique à l'environnement local. En savoir plus sur les classes d'opérateurs dans le manuel . Si vous utilisez les paramètres régionaux "C" standard (la plupart des gens ne le font pas), un index simple (avec la classe d'opérateur par défaut) fera l'affaire.
Un tel index n'est utile que pour les modèles ancrés à gauche (correspondant dès le début de la chaîne).
SIMILAR TO
ou des expressions régulières avec des expressions de base ancrées à gauche peuvent également utiliser cet index. Mais pas avec des branches (B|D)
ou des classes de caractères [BD]
(du moins dans mes tests sur PostgreSQL 9.0).
Les correspondances de trigrammes ou la recherche de texte utilisent des index spéciaux GIN ou GiST.
Vue d'ensemble des opérateurs de filtrage
LIKE
( ~~
) est simple et rapide, mais limité dans ses capacités.
ILIKE
( ~~*
) la variante insensible à la casse.
pg_trgm étend le support d'index pour les deux.
~
(correspondance d'expression régulière) est puissant mais plus complexe et peut être lent pour autre chose que des expressions de base.
SIMILAR TO
est juste inutile . Demi-sang particulier LIKE
et expressions régulières. Je ne l'utilise jamais. Voir ci-dessous.
% est l'opérateur de "similarité" fourni par le module supplémentairepg_trgm
. Voir ci-dessous.
@@
est l'opérateur de recherche de texte. Voir ci-dessous.
pg_trgm - correspondance de trigramme
À partir de PostgreSQL 9.1, vous pouvez faciliter l’extension pg_trgm
pour fournir un support d’index pour tout motif LIKE
/ ILIKE
pattern (et de simples modèles d’expression rationnelle avec ~
) à l’aide d’un index GIN ou GiST.
Détails, exemple et liens:
pg_trgm
fournit également ces opérateurs :
%
- l'opérateur "similitude"
<%
(commutateur %>
:) - l'opérateur "word_similarity" dans Postgres 9.6 ou version ultérieure
<<%
(commutateur %>>
:) - l'opérateur "strict_word_similarity" dans Postgres 11 ou version ultérieure
Recherche de texte
Est un type spécial de correspondance de modèle avec des types d’infrastructure et d’index séparés. Il utilise des dictionnaires et est un outil génial pour trouver des mots dans les documents, en particulier pour les langues naturelles.
La correspondance de préfixe est également prise en charge:
Ainsi que la recherche de phrase depuis Postgres 9.6:
Considérez l’ introduction dans le manuel et l’ aperçu des opérateurs et des fonctions .
Outils supplémentaires pour la correspondance de chaîne fuzzy
Le module supplémentaire fuzzystrmatch offre quelques options supplémentaires, mais les performances sont généralement inférieures à toutes les solutions ci-dessus.
En particulier, diverses implémentations de la levenshtein()
fonction peuvent être déterminantes.
Pourquoi les expressions régulières ( ~
) sont-elles toujours plus rapides que SIMILAR TO
?
La réponse est simple SIMILAR TO
les expressions sont réécrites en expressions régulières en interne. Ainsi, pour chaque SIMILAR TO
expression, il existe au moins une expression régulière plus rapide (qui évite la surcharge de la réécriture de l'expression). Il n'y a aucun gain de performance en utilisant SIMILAR TO
jamais .
Et de toute façon, les expressions simples pouvant être réalisées avec LIKE
( ~~
) sont plus rapides LIKE
.
SIMILAR TO
n’est supporté que par PostgreSQL car il s’est retrouvé dans les premières versions du standard SQL. Ils ne s'en sont toujours pas débarrassés. Mais il est prévu de l'enlever et d'inclure plutôt des correspondances d'expressions rationnelles - ou du moins l'ai-je entendu dire.
EXPLAIN ANALYZE
le révèle. Essayez juste avec n'importe quelle table vous-même!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Révèle:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
a été réécrit avec une expression régulière ( ~
).
Performance ultime pour ce cas particulier
Mais EXPLAIN ANALYZE
révèle plus. Essayez, avec l'index susmentionné en place:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Révèle:
...
-> 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))
En interne, avec un indice qui est locale-conscient de ne pas ( text_pattern_ops
ou à l' aide locale C
) simples expressions ancrées à gauche sont réécrites avec ces opérateurs de modèle de texte: ~>=~
, ~<=~
, ~>~
, ~<~
. C'est le cas pour ~
, ~~
ou SIMILAR TO
semblable.
Il en va de même pour les index sur les varchar
types avec varchar_pattern_ops
ou char
avec bpchar_pattern_ops
.
Donc, appliqué à la question initiale, c’est le moyen le plus rapide possible :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Bien sûr, s'il vous arrivait de rechercher des initiales adjacentes , vous pouvez simplifier:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Le gain par rapport à l'utilisation simple de ~
ou ~~
est minime. Si les performances ne sont pas votre exigence primordiale, vous devez simplement vous en tenir aux opérateurs standard pour arriver à ce que vous avez déjà dans la question.
s.name
indexé?