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

Kueri spasial pada tabel besar dengan beberapa self join berkinerja lambat

Kueri ini harus berjalan jauh (menjadi banyak lebih cepat):

WITH school AS (
   SELECT s.osm_id AS school_id, text 'school' AS type, s.osm_id, s.name, s.way_geo
   FROM   planet_osm_point s
        , LATERAL (
      SELECT  1 FROM planet_osm_point
      WHERE   ST_DWithin(way_geo, s.way_geo, 500, false)
      AND     amenity = 'bar'
      LIMIT   1  -- bar exists -- most selective first if possible
      ) b
        , LATERAL (
      SELECT  1 FROM planet_osm_point
      WHERE   ST_DWithin(way_geo, s.way_geo, 500, false)
      AND     amenity = 'restaurant'
      LIMIT   1  -- restaurant exists
      ) r
   WHERE  s.amenity = 'school'
   )
SELECT * FROM (
   TABLE school  -- schools

   UNION ALL  -- bars
   SELECT s.school_id, 'bar', x.*
   FROM   school s
        , LATERAL (
      SELECT  osm_id, name, way_geo
      FROM    planet_osm_point
      WHERE   ST_DWithin(way_geo, s.way_geo, 500, false)
      AND     amenity = 'bar'
      ) x

   UNION ALL  -- restaurants
   SELECT s.school_id, 'rest.', x.*
   FROM   school s
        , LATERAL (
      SELECT  osm_id, name, way_geo
      FROM    planet_osm_point
      WHERE   ST_DWithin(way_geo, s.way_geo, 500, false)
      AND     amenity = 'restaurant'
      ) x
   ) sub
ORDER BY school_id, (type <> 'school'), type, osm_id;

Ini bukan sama dengan kueri asli Anda, melainkan apa yang sebenarnya Anda inginkan, sesuai diskusi di komentar :

Jadi kueri ini mengembalikan daftar sekolah tersebut, diikuti oleh bar dan restoran terdekat. Setiap set baris disatukan oleh osm_id sekolah pada kolom school_id .

Sekarang menggunakan LATERAL bergabung, untuk memanfaatkan indeks spasial GiST.

TABLE school hanyalah singkatan dari SELECT * FROM school :

Ekspresi (type <> 'school') memesan sekolah di setiap set terlebih dahulu, karena:

Subkueri sub di akhir SELECT hanya diperlukan untuk memesan dengan ekspresi ini. Sebuah UNION kueri membatasi ORDER BY attached terlampir daftar ke kolom saja, tanpa ekspresi.

Saya fokus pada pertanyaan yang Anda sajikan untuk tujuan jawaban ini - mengabaikan persyaratan tambahan untuk memfilter pada salah satu dari 70 kolom teks lainnya. Itu benar-benar cacat desain. Kriteria pencarian harus terkonsentrasi di sedikit kolom. Atau Anda harus mengindeks semua 70 kolom, dan indeks multikolom seperti yang akan saya usulkan bukanlah pilihan. Masih mungkin meskipun ...

Indeks

Selain yang sudah ada:

"idx_planet_osm_point_waygeo" gist (way_geo)

Jika selalu memfilter pada kolom yang sama, Anda dapat membuat indeks multikolom mencakup beberapa kolom yang Anda minati, jadi index- hanya memindai menjadi mungkin:

CREATE INDEX planet_osm_point_bar_idx ON planet_osm_point (amenity, name, osm_id)

Postgres 9.5

Postgres mendatang 9.5 memperkenalkan perbaikan besar yang terjadi untuk menangani kasus Anda dengan tepat:

Itu sangat menarik bagi Anda. Sekarang Anda dapat memiliki tunggal multicolumn (mencakup) indeks GiST:

CREATE INDEX reservations_range_idx ON reservations
USING gist(amenity, way_geo, name, osm_id)

Dan:

Dan:

Mengapa? Karena ROLLUP akan menyederhanakan kueri yang saya sarankan. Jawaban terkait:

Versi alfa pertama telah dirilis pada 2 Juli 2015. Jadwal waktu rilis yang diharapkan:

Dasar

Tentu saja, pastikan untuk tidak mengabaikan dasar-dasarnya:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Di mana log PostgreSQL di macOS?

  2. Mengapa NULL tidak dapat dikonversi ke null JSON di postgreSQL?

  3. Pemicu acara ROLLBACK di postgresql

  4. Bagaimana cara membuat indeks unik dengan kondisional dan subquery di PostgreSQL?

  5. ProtocolViolation:ERROR:pesan ikat memasok 0 parameter, tetapi pernyataan yang disiapkan membutuhkan 1