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 TO
dalam kasus mana pun untuk saya.
Dengan indeks B-Tree yang sesuai di tempat, LIKE
memenangkan 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 TO
atau 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 TO
tidak ada gunanya . Halfbreed aneh LIKE
dan 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_trgm
untuk memberikan dukungan indeks untuk pola / apa saja (dan pola regexp sederhana ) menggunakan indeks GIN atau GiST.LIKE
ILIKE
~
Detail, contoh, dan tautan:
pg_trgm
juga 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 TO
ekspresi ditulis ulang menjadi ekspresi reguler secara internal. Jadi, untuk setiap SIMILAR TO
ekspresi, 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 LIKE
pula.
SIMILAR TO
hanya 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 ANALYZE
mengungkapkannya. 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 TO
telah ditulis ulang dengan ekspresi reguler ( ~
).
Kinerja terbaik untuk kasus khusus ini
Tetapi EXPLAIN ANALYZE
mengungkapkan 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_ops
atau menggunakan lokal C
) ekspresi kiri-berlabuh sederhana yang ditulis ulang dengan operator pola teks ini: ~>=~
, ~<=~
, ~>~
, ~<~
. Ini adalah kasus untuk ~
, ~~
atau SIMILAR TO
sama.
Hal yang sama berlaku untuk indeks pada varchar
tipe dengan varchar_pattern_ops
atau char
dengan 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.name
diindeks?