PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

LATERAL JOIN tidak menggunakan indeks trigram

Mengapa?

Kueri tidak dapat menggunakan indeks pada prinsipal. Anda akan membutuhkan indeks pada tabel locations , tetapi yang Anda miliki ada di tabel addresses .

Anda dapat memverifikasi klaim saya dengan menyetel:

SET enable_seqscan = off;

(Hanya dalam sesi Anda, dan hanya untuk debugging. Jangan pernah menggunakannya dalam produksi.) Ini tidak seperti indeks akan lebih mahal daripada pemindaian berurutan, tidak ada cara bagi Postgres untuk menggunakannya untuk kueri Anda sama sekali .

Selain:[INNER] JOIN ... ON true hanyalah cara yang canggung untuk mengatakan CROSS JOIN ...

Mengapa indeks digunakan setelah menghapus ORDER dan LIMIT ?

Karena Postgres dapat menulis ulang formulir sederhana ini menjadi:

SELECT *
FROM   addresses a
JOIN   locations l ON a.address ILIKE '%' || l.postalcode || '%';

Anda akan melihat paket kueri yang sama persis. (Setidaknya saya lakukan dalam pengujian saya di Postgres 9.5.)

Solusi

Anda memerlukan indeks di locations.postalcode . Dan saat menggunakan LIKE atau ILIKE anda juga perlu membawa ekspresi terindeks (postalcode ) ke kiri sisi operator. ILIKE diimplementasikan dengan operator ~~* dan operator ini tidak memiliki COMMUTATOR (kebutuhan logis), jadi tidak mungkin untuk membalik operan. Penjelasan terperinci dalam jawaban terkait ini:

Solusinya adalah dengan menggunakan operator kesamaan trigram % atau kebalikannya, operator jarak <-> di tetangga terdekat query sebagai gantinya (masing-masing adalah komutator untuk dirinya sendiri, sehingga operan dapat berpindah tempat dengan bebas):

SELECT *
FROM   addresses a
JOIN   LATERAL (
   SELECT *
   FROM   locations
   ORDER  BY postalcode <-> a.address
   LIMIT  1
   ) l ON address ILIKE '%' || postalcode || '%';

Temukan postalcode yang paling mirip untuk setiap addresses , lalu periksa apakah postalcode . itu benar-benar cocok sepenuhnya.

Dengan cara ini, postalcode yang lebih panjang akan lebih disukai secara otomatis karena lebih mirip (jarak lebih kecil) daripada postalcode yang lebih pendek yang juga cocok.

Sedikit ketidakpastian tetap ada. Tergantung pada kemungkinan kode pos, mungkin ada positif palsu karena trigram yang cocok di bagian lain dari string. Tidak ada informasi yang cukup dalam pertanyaan untuk mengatakan lebih banyak.

Disini , [INNER] JOIN alih-alih CROSS JOIN masuk akal, karena kami menambahkan kondisi gabungan yang sebenarnya.

Manual:

Jadi:

CREATE INDEX locations_postalcode_trgm_gist_idx ON locations
USING gist (postalcode gist_trgm_ops);


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Memahami Dan Membaca Katalog Sistem PostgreSQL

  2. `initialize':skema postgres tidak menerima bagian registri:postgres:@ (atau nama host yang buruk?) (URI::InvalidURIError) dengan Docker

  3. Tugas Rake Heroku Rails untuk Menyinkronkan Produksi &DB Lokal

  4. Di Rails, Tidak dapat membuat database untuk {adapter=>postgresql,

  5. Apakah PLV8 mendukung membuat panggilan http ke server lain?