Permintaan Anda cukup optimal. Sintaks tidak akan menjadi jauh lebih pendek, permintaan tidak akan menjadi jauh lebih cepat:
SELECT name
FROM spelers
WHERE name LIKE 'B%' OR name LIKE 'D%'
ORDER BY 1;
Jika Anda benar-benar ingin mempersingkat sintaks , gunakan ekspresi reguler dengan cabang :
...
WHERE name ~ '^(B|D).*'
Atau sedikit lebih cepat, dengan kelas karakter :
...
WHERE name ~ '^[BD].*'
Pengujian cepat tanpa indeks menghasilkan hasil yang lebih cepat daripada SIMILAR TOdalam kasus mana pun untuk saya.
Dengan indeks B-Tree yang sesuai di tempat, LIKEmemenangkan perlombaan ini dengan urutan besarnya.
Baca dasar-dasar tentang pencocokan pola dalam manual .
Indeks untuk kinerja yang unggul
Jika Anda khawatir dengan kinerja, buat indeks seperti ini untuk tabel yang lebih besar:
CREATE INDEX spelers_name_special_idx ON spelers (name text_pattern_ops);
Membuat kueri semacam ini lebih cepat dengan perintah besarnya. Pertimbangan khusus berlaku untuk urutan sortir khusus-lokal. Baca lebih lanjut tentang kelas operator di manual . Jika Anda menggunakan lokal "C" standar (kebanyakan orang tidak), indeks biasa (dengan kelas operator default) akan dilakukan.
Indeks semacam itu hanya baik untuk pola berlabuh kiri (cocok dari awal string).
SIMILAR TOatau ekspresi reguler dengan ekspresi dasar berlabuh kiri dapat menggunakan indeks ini juga. Tetapi tidak dengan cabang (B|D)atau kelas karakter [BD](setidaknya dalam tes saya pada PostgreSQL 9.0).
Pencocokan trigram atau pencarian teks menggunakan indeks GIN atau GiST khusus.
Gambaran umum operator pencocokan pola
LIKE( ~~) Sederhana dan cepat tetapi terbatas dalam kemampuannya.
ILIKE( ~~*) varian case sensitif.
pg_trgm memperluas dukungan indeks untuk keduanya.
~ (pencocokan ekspresi reguler) sangat kuat tetapi lebih kompleks dan mungkin lambat untuk apa pun selain ekspresi dasar.
SIMILAR TOtidak ada gunanya . Halfbreed aneh LIKEdan ekspresi reguler. Saya tidak pernah menggunakannya. Lihat di bawah.
% adalah operator "kesamaan", yang disediakan oleh modul tambahanpg_trgm. Lihat di bawah.
@@adalah operator pencarian teks. Lihat di bawah.
pg_trgm - pencocokan trigram
Dimulai dengan PostgreSQL 9.1 Anda dapat memfasilitasi ekstensi pg_trgmuntuk memberikan dukungan indeks untuk pola / apa saja (dan pola regexp sederhana ) menggunakan indeks GIN atau GiST.LIKEILIKE~
Detail, contoh, dan tautan:
pg_trgmjuga menyediakan operator ini :
% - operator "kesamaan"
<%(komutator %>:) - operator "word_similarity" di Postgres 9.6 atau lebih baru
<<%(komutator %>>:) - operator "strict_word_similarity" di Postgres 11 atau lebih baru
Pencarian Teks
Merupakan jenis khusus pencocokan pola dengan infrastruktur dan tipe indeks terpisah. Ini menggunakan kamus dan stemming dan merupakan alat yang hebat untuk menemukan kata-kata dalam dokumen, terutama untuk bahasa alami.
Pencocokan awalan juga didukung:
Serta pencarian frasa sejak Postgres 9.6:
Pertimbangkan pengantar dalam manual dan ikhtisar operator dan fungsi .
Alat tambahan untuk pencocokan string fuzzy
Modul fuzzystrmatch tambahan menawarkan beberapa opsi lebih banyak, tetapi kinerja umumnya lebih rendah daripada semua yang di atas.
Secara khusus, berbagai implementasi levenshtein()fungsi dapat berperan.
Mengapa ekspresi reguler ( ~) selalu lebih cepat daripada SIMILAR TO?
Jawabannya sederhana. SIMILAR TOekspresi ditulis ulang menjadi ekspresi reguler secara internal. Jadi, untuk setiap SIMILAR TOekspresi, setidaknya ada satu ekspresi reguler yang lebih cepat (yang menghemat biaya penulisan ulang ekspresi). Tidak ada keuntungan kinerja dalam menggunakan SIMILAR TO pernah .
Dan ekspresi sederhana yang dapat dilakukan dengan LIKE( ~~) lebih cepat LIKEpula.
SIMILAR TOhanya didukung di PostgreSQL karena berakhir pada konsep awal standar SQL. Mereka masih belum menyingkirkannya. Tapi ada rencana untuk menghapusnya dan memasukkan pertandingan regexp - atau begitulah yang saya dengar.
EXPLAIN ANALYZEmengungkapkannya. Coba saja dengan meja apa saja sendiri!
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name SIMILAR TO 'B%';
Mengungkapkan:
...
Seq Scan on spelers (cost= ...
Filter: (name ~ '^(?:B.*)$'::text)
SIMILAR TOtelah ditulis ulang dengan ekspresi reguler ( ~).
Kinerja terbaik untuk kasus khusus ini
Tetapi EXPLAIN ANALYZEmengungkapkan lebih banyak. Coba, dengan indeks yang disebutkan sebelumnya di tempat:
EXPLAIN ANALYZE SELECT * FROM spelers WHERE name ~ '^B.*;
Mengungkapkan:
...
-> 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))
Secara internal, dengan indeks yang tidak locale-sadar ( text_pattern_opsatau menggunakan lokal C) ekspresi kiri-berlabuh sederhana yang ditulis ulang dengan operator pola teks ini: ~>=~, ~<=~, ~>~, ~<~. Ini adalah kasus untuk ~, ~~atau SIMILAR TOsama.
Hal yang sama berlaku untuk indeks pada varchartipe dengan varchar_pattern_opsatau chardengan bpchar_pattern_ops.
Jadi, diterapkan pada pertanyaan awal, ini adalah cara tercepat yang mungkin :
SELECT name
FROM spelers
WHERE name ~>=~ 'B' AND name ~<~ 'C'
OR name ~>=~ 'D' AND name ~<~ 'E'
ORDER BY 1;
Tentu saja, jika Anda kebetulan mencari inisial yang berdekatan , Anda dapat menyederhanakan lebih lanjut:
WHERE name ~>=~ 'B' AND name ~<~ 'D' -- strings starting with B or C
Keuntungan atas penggunaan sederhana ~atau ~~kecil. Jika kinerja bukan persyaratan utama Anda, Anda harus tetap menggunakan operator standar - sampai pada apa yang sudah Anda miliki dalam pertanyaan.
s.namediindeks?