sql >> Databasteknik >  >> RDS >> PostgreSQL

Rumslig fråga på ett stort bord med flera självkopplingar som fungerar långsamt

Den här frågan borde räcka långt (vara mycket snabbare):

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;

Detta är inte samma som din ursprungliga fråga, utan snarare vad du faktiskt vill ha, enligt diskussion i kommentarer :

Så den här frågan returnerar en lista över dessa skolor, följt av barer och restauranger i närheten. Varje uppsättning rader hålls samman av osm_id av skolan i kolumnen school_id .

Använder nu LATERAL joins, för att använda det rumsliga GiST-indexet.

TABELL skola är bara en förkortning för SELECT * FROM school :

Uttrycket (typ <> 'skola') beställer skolan i varje set först, eftersom:

Underfrågan sub i den sista SELECT behövs bara för att beställa efter detta uttryck. En UNION fråga begränsar en bifogad ORDER BY lista till endast kolumner, inga uttryck.

Jag fokuserar på frågan du presenterade för detta svar - ignorera det utökade kravet att filtrera på någon av de andra 70 textkolumnerna. Det är verkligen ett designfel. Sökkriterierna bör koncentreras till kolumner. Eller så måste du indexera alla 70 kolumner, och flerkolumnsindex som jag kommer att föreslå är knappast ett alternativ. Fortfarande möjligt fast ...

Index

Förutom de befintliga:

"idx_planet_osm_point_waygeo" gist (way_geo)

Om du alltid filtrerar på samma kolumn kan du skapa en flerkolumnsindex täcker de få kolumner du är intresserad av, så index- endast skannar bli möjligt:

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

Postgres 9.5

Den kommande Postgres 9.5 introducerar stora förbättringar som råkar adressera ditt fall exakt:

Det är av särskilt intresse för dig. Nu kan du ha en singel flerkolumn (täckande) GiST-index:

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

Och:

Och:

Varför? Eftersom ROLLUP skulle förenkla frågan jag föreslog. Relaterat svar:

Den första alfaversionen har släppts den 2 juli 2015. Den förväntade tidslinjen för releasen:

Grunderna

Naturligtvis, se till att inte förbise grunderna:



  1. Problem med att kontrollera om en tabell finns eller inte i db

  2. Spring Boot REST · @Constraint för radering?

  3. Hur man läser MySQL binära loggfiler (BinLog) med mysqlbinlog

  4. mysqli infoga - men bara om det inte är en dubblett