Sorgunuz hemen hemen en uygunudur. Sözdizimi çok daha kısa olmayacak, sorgu çok daha hızlı olmayacak:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Sözdizimini gerçekten kısaltmak istiyorsanız , dallarla düzenli bir ifade kullanın :
...
WHERE name ~ '^(B|D).*'
Veya bir karakter sınıfıyla biraz daha hızlı :
...
WHERE name ~ '^[BD].*'
İndekssiz hızlı bir test SIMILAR TO
, her iki durumda da benim için olduğundan daha hızlı sonuç verir .
Uygun bir B-Tree endeksi mevcut olduğunda, LIKE
bu yarışı büyüklük derecelerine göre kazanır.
Kılavuzdaki desen eşleşmeyle ilgili temel bilgileri okuyun .
Üstün performans için endeks
Performansla ilgileniyorsanız, daha büyük tablolar için böyle bir dizin oluşturun:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Bu tür bir sorguyu büyüklük sırasına göre daha hızlı hale getirir. Yerellere özgü sıralama düzeni için özel hususlar uygulanır. Kılavuzdaki operatör sınıfları hakkında daha fazla bilgi edinin . Standart "C" yerel ayarını kullanıyorsanız (çoğu insan kullanmaz), düz bir dizin (varsayılan operatör sınıfına sahip) yapar.
Böyle bir indeks sadece sol bağlantılı desenler için iyidir (dizgenin başından itibaren).
SIMILAR TO
veya temel sol bağlantılı ifadelere sahip normal ifadeler de bu dizini kullanabilir. Ama değil şubesi bulunan (B|D)
veya karakter sınıfları [BD]
(en azından PostgreSQL 9.0 benim testleri olarak).
Trigram eşleşmeleri veya metin araması, özel GIN veya GiST dizinlerini kullanır.
Desen eşleştirme işleçlerine genel bakış
LIKE
( ~~
) basit ve hızlıdır ancak yetenekleri sınırlıdır.
ILIKE
( ~~*
) durumda duyarsız değişken.
pg_trgm, her ikisi için de dizin desteğini genişletir.
~
(düzenli ifade eşleşmesi) güçlüdür ancak daha karmaşıktır ve temel ifadelerden daha fazlası için yavaş olabilir.
SIMILAR TO
sadece anlamsız . Tuhaf bir melez LIKE
ve düzenli ifadeler. Asla kullanmam. Aşağıya bakınız.
% ek modül tarafından sağlanan "benzerlik" işlecidirpg_trgm
. Aşağıya bakınız.
@@
Metin arama operatörüdür. Aşağıya bakınız.
pg_trgm - trigram eşleştirme
PostgreSQL 9.1'den başlayarak, bir GIN veya GiST endeksi kullanarak herhangi bir / desen (ve basit regexp desenleri ) pg_trgm
için dizin desteği sağlama uzantısını kolaylaştırabilirsiniz . LIKE
ILIKE
~
Ayrıntılar, örnek ve bağlantılar:
pg_trgm
Ayrıca bu operatörleri sağlar :
%
- "benzerlik" operatörü
<%
(komütatör %>
:) - Postgres 9.6 veya sonraki sürümlerde "word_similarity" operatörü
<<%
(komütatör %>>
:) - Postgres 11 veya sonraki sürümlerde "strict_word_similarity" operatörü
Metin arama
Ayrı altyapı ve indeks tipleri ile özel bir desen eşleşmesidir. Sözlükleri kullanır ve kaynak gösterir ve özellikle doğal diller için belgelerdeki kelimeleri bulmak için harika bir araçtır.
Ön ek eşleştirme de desteklenir:
Postgres 9.6’dan beri yapılan kelime öbeğinin yanı sıra :
Kılavuzdaki girişleri ve operatörlere ve fonksiyonlara genel bakışı düşünün .
Bulanık dize eşleşmesi için ek araçlar
Ek modül fuzzystrmatch bazı daha fazla seçenek sunar, ancak performans genellikle yukarıdakilerin hepsinden daha düşüktür.
Özellikle, levenshtein()
fonksiyonun çeşitli uygulamaları araçsal olabilir.
Düzenli ifadeler ( ~
) neden her zaman daha hızlı SIMILAR TO
?
Cevap basit. SIMILAR TO
ifadeler dahili olarak normal ifadelere yeniden yazılır. Bu nedenle, her SIMILAR TO
ifade için , en az bir daha hızlı düzenli ifade vardır (bu, ifadeyi yeniden yazma yükünü korur). Kullanmada hiçbir performans kazancı yoktur SIMILAR TO
hiç .
Ve LIKE
( ~~
) ile yapılabilecek basit ifadeler LIKE
yine de daha hızlıdır .
SIMILAR TO
SQL standardının ilk taslaklarında ortaya çıktığı için yalnızca PostgreSQL'de desteklenir. Hala ondan kurtulmadılar. Ancak bunu kaldırmak ve bunun yerine regexp eşleşmeleri eklemek için planlar var - ya da öyle duydum.
EXPLAIN ANALYZE
onu ortaya koyuyor. Sadece herhangi bir masayı kendiniz deneyin!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
ortaya çıkarır:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TO
düzenli bir ifadeyle ( ~
) yeniden yazılmıştır .
Bu özel durum için üstün performans
Ancak EXPLAIN ANALYZE
daha fazlasını ortaya koyuyor. Yukarıda belirtilen endeks yerindeyken deneyin:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
ortaya çıkarır:
...
-> 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))
Dahili olarak, bir yerele farkında değildir indeksi (ile text_pattern_ops
veya kullanarak yerel C
:) basit sol demirlemiş ifadeleri bu metin desen operatörleri ile yeniden yazıldı ~>=~
, ~<=~
, ~>~
, ~<~
. Bu ~
, ~~
ya da SIMILAR TO
benzerleri için geçerlidir.
Aynısı ya da ile olan varchar
türlerdeki dizinler için de geçerlidir .varchar_pattern_ops
char
bpchar_pattern_ops
Yani, orijinal soruya uygulandığında, bu en hızlı yoldur :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Tabii ki, bitişik baş harfleri aramanız gerekirse, daha da basitleştirebilirsiniz:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Sade kullanımı ~
ya da ~~
çok küçük kazancı . Performans, en önemli gereksiniminiz değilse, standart operatörlere bağlı kalmalısınız - soruya zaten sahip olduğunuz şeye ulaştınız.
s.name
endeksli?