sql >> Database >  >> RDS >> PostgreSQL

Ruimtelijke query op grote tafel met meerdere self-joins die traag werken

Deze zoekopdracht zou een lange weg moeten gaan (be veel sneller):

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;

Dit is niet hetzelfde als uw oorspronkelijke vraag, maar eerder wat u eigenlijk wilt, volgens discussie in opmerkingen :

Deze zoekopdracht retourneert dus een lijst van die scholen, gevolgd door bars en restaurants in de buurt. Elke reeks rijen wordt bij elkaar gehouden door de osm_id van de school in de kolom school_id .

Gebruikt nu LATERAL joins, om gebruik te maken van de ruimtelijke GiST-index.

TABLE school is gewoon een afkorting voor SELECT * FROM school :

De uitdrukking (type <> 'school') bestelt eerst de school in elke set, omdat:

De subquery sub in de laatste SELECT is alleen nodig om te bestellen met deze uitdrukking. Een UNION query beperkt een bijgevoegde ORDER BY lijst naar alleen kolommen, geen uitdrukkingen.

Ik concentreer me op de vraag die u heeft gesteld voor dit antwoord - negeren de uitgebreide vereiste om te filteren op een van de andere 70 tekstkolommen. Dat is echt een ontwerpfout. De zoekcriteria moeten worden geconcentreerd in enkele kolommen. Of je moet alle 70 kolommen indexeren, en indexen met meerdere kolommen, zoals ik ga voorstellen, zijn nauwelijks een optie. Nog mogelijk hoewel ...

Index

Naast de bestaande:

"idx_planet_osm_point_waygeo" gist (way_geo)

Als u altijd op dezelfde kolom filtert, kunt u een maken index met meerdere kolommen voor de paar kolommen waarin u geïnteresseerd bent, dus index- scant alleen mogelijk worden:

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

Postgres 9.5

De komende Postgres 9.5 introduceert grote verbeteringen die toevallig uw zaak precies behandelen:

Dat is voor jou van bijzonder belang. Nu kunt u een enkele . hebben multicolumn (bedekkende) GiST-index:

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

En:

En:

Waarom? Omdat ROLLUP zou de door mij voorgestelde vraag vereenvoudigen. Gerelateerd antwoord:

De eerste alfaversie is uitgebracht op 2 juli 2015. De verwachte tijdlijn voor de release:

Basis

Zorg er natuurlijk voor dat u de basis niet over het hoofd ziet:



  1. Hoe verbreek je alle huidige verbindingen met een SQL Server 2005-database?

  2. MySQL converteert CHAR (32) datatype naar BINARY (16) zonder gegevens te verliezen

  3. Hoe voer ik databasetransacties uit met psycopg2/python db api?

  4. Grote objectgegevens invoegen in Salesforce.com vanuit SQL Server