sql >> Databáze >  >> RDS >> PostgreSQL

Prostorový dotaz na velké tabulce s vícenásobnými vlastními spojeními je pomalý

Tento dotaz by měl jít dlouhou cestou (být hodně rychlejší):

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;

Toto není stejné jako váš původní dotaz, ale spíše to, co skutečně chcete, dle diskuze v komentářích :

Tento dotaz tedy vrátí seznam těchto škol následovaný bary a restauracemi v okolí. Každá sada řádků je držena pohromadě pomocí osm_id školy ve sloupci id_školy .

Nyní pomocí LATERAL spojení, aby bylo možné využít prostorový index GiST.

TABLE škola je jen zkratka pro SELECT * FROM school :

Výraz (typ <> 'škola') objednává školu v každé sadě jako první, protože:

Poddotaz sub ve finálním SELECT je potřeba pouze objednat tímto výrazem. UNION dotaz omezuje připojený ORDER BY seznam pouze na sloupce, žádné výrazy.

Zaměřuji se na dotaz, který jste uvedli pro účely této odpovědi - ignorování rozšířený požadavek na filtrování podle kteréhokoli z dalších 70 textových sloupců. To je opravdu konstrukční vada. Kritéria vyhledávání by měla být soustředěna do několika sloupců. Nebo budete muset indexovat všech 70 sloupců a vícesloupcové indexy, jako budu navrhovat, jsou jen stěží možností. Stále možné ačkoli ...

Index

Kromě stávajícího:

"idx_planet_osm_point_waygeo" gist (way_geo)

Pokud vždy filtrujete podle stejného sloupce, můžete vytvořit vícesloupcový index pokrývající několik sloupců, které vás zajímají, takže index- pouze skenuje staly možnými:

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

Postgres 9.5

Nadcházející Postgres 9.5 představuje hlavní vylepšení které přesně řeší váš případ:

To tě obzvlášť zajímá. Nyní můžete mít single vícesloupcový (krycí) index GiST:

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

A:

A:

Proč? Protože ROLLUP by zjednodušil dotaz, který jsem navrhl. Související odpověď:

První alfa verze byla vydána 2. července 2015. Očekávaný časový rozvrh vydání:

Základy

Samozřejmě nezapomeňte na základní věci:



  1. Jak mohu zahrnout čáry přerušení do záznamů mysql?

  2. Práce s SQL kurzory

  3. Automaticky odstranit vrácené e-mailové adresy z databáze?

  4. Použití výmluvných polymorfních vztahů ke kategorizaci dat v Laravelu