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, LIKEbu 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 TOveya 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 TOsadece anlamsız . Tuhaf bir melez LIKEve 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_trgmiçin dizin desteği sağlama uzantısını kolaylaştırabilirsiniz . LIKEILIKE~
Ayrıntılar, örnek ve bağlantılar:
pg_trgmAyrı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 TOifadeler dahili olarak normal ifadelere yeniden yazılır. Bu nedenle, her SIMILAR TOifade 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 LIKEyine de daha hızlıdır .
SIMILAR TOSQL 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 ANALYZEonu 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 TOdüzenli bir ifadeyle ( ~) yeniden yazılmıştır .
Bu özel durum için üstün performans
Ancak EXPLAIN ANALYZEdaha 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_opsveya kullanarak yerel C:) basit sol demirlemiş ifadeleri bu metin desen operatörleri ile yeniden yazıldı ~>=~, ~<=~, ~>~, ~<~. Bu ~, ~~ya da SIMILAR TObenzerleri için geçerlidir.
Aynısı ya da ile olan varchartürlerdeki dizinler için de geçerlidir .varchar_pattern_opscharbpchar_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.nameendeksli?