PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Zapytanie przestrzenne na dużej tabeli z wieloma niezależnymi sprzężeniami działa wolno

To zapytanie powinno zająć dużo czasu (być dużo szybciej):

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;

To nie takie samo jak oryginalne zapytanie, ale raczej to, czego faktycznie chcesz, zgodnie z dyskusją w komentarzach :

To zapytanie zwraca więc listę tych szkół, a następnie pobliskich barów i restauracji. Każdy zestaw wierszy jest utrzymywany razem przez osm_id szkoły w kolumnie school_id .

Teraz używam LATERAL łączy, aby wykorzystać przestrzenny indeks GiST.

Table szkoła to tylko skrót od SELECT * FROM school :

Wyrażenie (wpisz <> 'szkoła') najpierw zamawia szkołę w każdym zestawie, ponieważ:

Podzapytanie sub w końcowym SELECT jest potrzebne tylko do uporządkowania według tego wyrażenia. ZWIĄZEK zapytanie ogranicza dołączone ORDER BY lista tylko do kolumn, bez wyrażeń.

Skupiam się na zapytaniu, które przedstawiłeś w celu udzielenia tej odpowiedzi – ignorowanie rozszerzony wymóg filtrowania według dowolnej z pozostałych 70 kolumn tekstowych. To naprawdę wada projektowa. Kryteria wyszukiwania powinny być skoncentrowane w niewielu kolumny. Albo będziesz musiał zaindeksować wszystkie 70 kolumn, a indeksy wielokolumnowe, które zamierzam zaproponować, nie są żadną opcją. Nadal możliwe chociaż ...

Indeks

Oprócz istniejących:

"idx_planet_osm_point_waygeo" gist (way_geo)

Jeśli zawsze filtrujesz tę samą kolumnę, możesz utworzyć indeks wielokolumnowy obejmujące kilka interesujących Cię kolumn, więc index- tylko skanuje stać się możliwe:

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

Postgres 9.5

Nadchodzący Postgres 9,5 wprowadza duże ulepszenia które dokładnie odpowiadają Twojej sprawie:

To dla ciebie szczególnie interesujące. Teraz możesz mieć singiel wielokolumnowy (zakrywający) indeks GiST:

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

Oraz:

Oraz:

Czemu? Ponieważ ROLLUP uprościłoby zapytanie, które zasugerowałem. Powiązana odpowiedź:

Pierwsza wersja alfa została wydana 2 lipca 2015 r. Przewidywany harmonogram wydania:

Podstawy

Oczywiście nie zapomnij o podstawach:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kolumna „mary” nie istnieje

  2. PostgreSQL - nie można zidentyfikować operatora równości dla typu json

  3. Jak zmapować Postgres _INT8 na encję Java za pomocą Hibernate?

  4. KOPIUJ z dynamiczną nazwą pliku

  5. Połącz się z bazą danych heroku za pomocą pgadmin