it-swarm.asia

Bagaimana cara membuat indeks untuk mempercepat permintaan LIKE agregat pada ekspresi?

Saya mungkin mengajukan pertanyaan yang salah dalam judul. Berikut ini faktanya:

Pelanggan layanan pelanggan saya mengeluhkan waktu respons yang lambat ketika melakukan pencarian pelanggan pada antarmuka administrasi situs berbasis Django kami.

Kami menggunakan Postgres 8.4.6. Saya mulai mencatat kueri lambat, dan menemukan penyebabnya:

SELECT COUNT(*) FROM "auth_user" WHERE UPPER("auth_user"."email"::text) LIKE UPPER(E'%deyk%')

Kueri ini membutuhkan waktu hingga 32 detik untuk dijalankan. Inilah paket kueri yang disediakan oleh EXPLAIN:

QUERY PLAN
Aggregate  (cost=205171.71..205171.72 rows=1 width=0)
  ->  Seq Scan on auth_user  (cost=0.00..205166.46 rows=2096 width=0)
        Filter: (upper((email)::text) ~~ '%DEYK%'::text)

Karena ini adalah permintaan yang dihasilkan oleh Django ORM dari Django QuerySet dihasilkan oleh Django aplikasi Admin, saya tidak tidak memiliki kontrol atas permintaan itu sendiri. Indeks tampaknya seperti solusi logis. Saya mencoba membuat indeks untuk mempercepat ini, tetapi belum membuat perbedaan:

CREATE INDEX auth_user_email_upper ON auth_user USING btree (upper(email::text))

Apa yang saya lakukan salah? Bagaimana saya bisa mempercepat permintaan ini?

22
David Eyk

Tidak ada dukungan indeks untuk LIKE/ILIKE in PostgreSQL 8.4 - kecuali untuk pencarian berlabuh kiri ketentuan .

Sejak PostgreSQL 9.1 modul tambahan pg_trgm memberikan kelas operator untuk indeks trigram GIN dan Gist yang mendukung LIKE/ILIKE atau ekspresi reguler (operator ~ dan teman-teman). Instal sekali per basis data:

CREATE EXTENSION pg_trgm;

Contoh indeks GIN:

CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);

Terkait:

24

Indeks itu tidak akan membantu karena '%' di awal pertandingan Anda - indeks BTREE hanya dapat mencocokkan awalan dan wildcard di awal kueri Anda berarti tidak ada awalan tetap yang harus dicari.

Itu sebabnya ia melakukan pemindaian tabel dan mencocokkan setiap catatan pada gilirannya dengan string kueri.

Anda mungkin perlu melihat menggunakan indeks teks lengkap dan operator pencocokan teks daripada melakukan pencarian substring dengan SEPERTI bahwa Anda saat ini. Anda dapat menemukan lebih banyak tentang pencarian teks lengkap dalam dokumentasi:

http://www.postgresql.org/docs/8.4/static/textsearch-intro.html

Bahkan saya perhatikan dari halaman itu bahwa LIKE tampaknya tidak pernah menggunakan indeks, yang bagi saya aneh karena harus dapat menyelesaikan awalan non-wildcard menggunakan indeks BTREE. Namun, beberapa tes cepat menunjukkan bahwa dokumentasi mungkin benar, dalam hal ini tidak ada jumlah pengindeksan yang akan membantu saat Anda menggunakan LIKE untuk menyelesaikan kueri.

9
TomH