sql >> データベース >  >> RDS >> PostgreSQL

複数の自己結合を使用した大きなテーブルでの空間クエリの実行速度が遅い

    このクエリは大いに役立つはずです(多く より速い):

    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;
    

    これはではありません 元のクエリと同じですが、実際に必要なものは、コメントでの議論による

    したがって、このクエリはそれらの学校のリストを返し、その後に近くのバーやレストランが続きます。行の各セットは、 osm_idによってまとめられています。 列school_idの学校の 。

    現在、 LATERALを使用しています 結合し、空間GiSTインデックスを利用します。

    テーブルスクール SELECT * FROM schoolの省略形です :

    (type <>'school') 次の理由により、各セットの学校を最初に注文します。

    サブクエリsub 最後のSELECT この式で注文する場合にのみ必要です。 UNION クエリは、添付された ORDER BYを制限します 列のみにリストし、式はありません。

    この回答の目的で提示したクエリに焦点を当てます-無視 他の70のテキスト列のいずれかでフィルタリングするための拡張要件。それは本当に設計上の欠陥です。検索条件は少数に集中する必要があります 列。または、70列すべてにインデックスを付ける必要があり、私が提案するような複数列のインデックスはほとんどオプションではありません。それでも可能 でも...

    インデックス

    既存のものに加えて:

    "idx_planet_osm_point_waygeo" gist (way_geo)
    

    常に同じ列でフィルタリングする場合は、 を作成できます。複数列のインデックス 関心のあるいくつかの列をカバーしているので、 index-スキャンのみ 可能になる:

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

    Postgres 9.5

    今後のPostgres9.5 主な改善点を紹介します それはたまたまあなたのケースに正確に対処します:

    それはあなたにとって特に興味深いことです。これで、シングルを作成できます 複数列(カバー)GiSTインデックス:

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

    そして:

    そして:

    なんで? ROLLUP 私が提案したクエリを単純化するでしょう。関連する回答:

    最初のアルファバージョンは2015年7月2日にリリースされました。リリースの予定タイムライン:

    基本

    もちろん、基本を見逃さないように注意してください:



    1. 数値(22,21)をBigDecimalにマッピングすると、結果の精度が休止状態で失われます

    2. PHPで複数のmysqlクエリを一緒に実行する方法は?

    3. PythonのMySQL:UnicodeEncodeError:'ascii'

    4. 主キーテーブルの行が重複しています。