空間関数による行の制限


9

以下のクエリのパフォーマンスを改善しようとしています。クエリ(FROM句のサブクエリ、WHERE句のサブクエリ)をどのように記述しても、countery = 24の行が60行しかないにもかかわらず、高価なST_DWITHIN関数ですべての570K行を実行するように要求します。postgresにcounty = 24でフィルターをかけるようにするには、postgis funcを実行する前にどのようにすればよいですか?700msはあまり心配する必要はありませんが、このテーブルが1,000万回以上になると、パフォーマンスが心配になります。

また、p.idは主キー、p.zipcodeはfkインデックス、z.countyはfkインデックス、p.geomはGiSTインデックスです。

クエリ:

EXPLAIN ANALYZE
  SELECT count(p.id)
  FROM point AS p
  LEFT JOIN zipcode AS z
    ON p.zipcode = z.zipcode
  WHERE z.county = 24
    AND ST_DWithin(
      p.geom, 
      ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269), 
      16090.0,
      false
    )

分析の説明:

Aggregate  (cost=250851.91..250851.92 rows=1 width=4) (actual time=724.007..724.007 rows=1 loops=1)
  ->  Hash Join  (cost=152.05..250851.34 rows=228 width=4) (actual time=0.359..723.996 rows=51 loops=1)
        Hash Cond: ((p.zipcode)::text = (z.zipcode)::text)
        ->  Seq Scan on point p  (cost=0.00..250669.12 rows=7437 width=10) (actual time=0.258..723.867 rows=63 loops=1)
              Filter: (((geom)::geography && '0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography) AND ('0101000020AD10000063DF8B52B45E5EC070FB752018484340'::geography && _st_expand((geom)::geography, 16090::double precision)) AND _st_dwithin((g (...)
              Rows Removed by Filter: 557731
        ->  Hash  (cost=151.38..151.38 rows=54 width=6) (actual time=0.095..0.095 rows=54 loops=1)
              Buckets: 1024  Batches: 1  Memory Usage: 3kB
              ->  Bitmap Heap Scan on zipcode z  (cost=4.70..151.38 rows=54 width=6) (actual time=0.023..0.079 rows=54 loops=1)
                    Recheck Cond: (county = 24)
                    Heap Blocks: exact=39
                    ->  Bitmap Index Scan on fki_zipcode_county_foreign_key  (cost=0.00..4.68 rows=54 width=0) (actual time=0.016..0.016 rows=54 loops=1)
                          Index Cond: (county = 24)
Planning time: 0.504 ms
Execution time: 724.064 ms

「point as p left join zipcode as z」のような行を「point as p left join(SELECT * FROM zipcode WHERE zipcode.county = 24)as z」のように変更してみてください。
weiji14

試してみましたが、同じ結果です。pointcounty = 24の〜60 行をすべて新しいテーブルにコピーすると、クエリは724と比較して.453msしかかかりませんので、明らかに大きな違いがあります。
Josh、

1
count(*)スタイルの問題として使用する必要があります。idあなたが言うようにpkid なら、それNOT NULLはそれらが同じであることを意味します。を除いcount(id)て、idnullが可能かどうかを質問する必要があるという欠点があります。
エヴァンキャロル2017年

1
なぜ左外部結合を使用しているのですか?内部結合に変更してみてください...結果は同じである必要があります
MickyT

z.countryが制限要因である場合は、これを最初にCTEクエリに入れてから、それらの結果と関心のあるポイントとの交差を確認することをお勧めします。この場合、空間インデックスは郡= 24よりも選択性が低いため、邪魔になるだけです。
John Powell

回答:


3

予想される行数と実際の行数の問題を確認できます。プランナーは7,437行あると考えていますが、63行しかありません。統計はオフです。興味深いことに、バウンディングボックスインデックス(インデックス)検索を使用していないDWithinため、の結果を貼り付けることができます\d point。PostGISとPostgreSQLのバージョンは何ですか?

実行してみてくださいANALYZE point。状態を上に上げても同じプランになりますか?

JOIN zipcode AS z
  ON p.zipcode = z.zipcode
  AND z.county = 24

私は分析を実行し、ONで新しいAND条件を試しましたが、それでも700msの実行時間を得ていました。これはPGSQL 9.4およびPostGIS 2.2です。
ジョシュ

2

注意点として、そこにある合理的なバグ、それを呼び出すようにしたい場合は、この動作は、PostGISの2.3.0で修正される可能性が。

PostgreSQLドキュメントから

cpu_operator_costの単位で、関数の推定実行コストを示す正の数。関数がセットを返す場合、これは返される行あたりのコストです。コストが指定されていない場合、C言語および内部関数には1ユニット、他のすべての言語の関数には100ユニットが想定されます。値が大きいと、プランナは必要以上に頻繁に関数を評価しないようにします。

したがって、デフォルトのコストは1(非常に安い)でした。D_WithinGISTインデックスの使用は非常に安価です。しかし、それは100に増加しました(内部のプロキシによって_ST_DWithin)。

私自身、CTEメソッドの大ファンではありません。CTEは最適化フェンスです。そのため、このような方法でこれを行うと、将来の最適化の潜在的な余地がなくなります。saner defaultsがそれを修正するなら、私はむしろアップグレードしたいと思います。結局のところ、私たちは仕事を成し遂げる必要があり、その方法は明らかにあなたのために機能します。


1

John Powellのヒントのおかげで、with / CTEクエリに郡の制限条件を追加するようにクエリを修正し、これによりパフォーマンスが700対222ミリ秒とかなり向上しました。データがその中にあるときの0.74ミリ秒とはかなり異なります自分のテーブル。なぜプランナーが高価なpostgis関数を実行する前にデータセットを制限しないのかまだわからないので、大きなデータセットがある場合はそれを試す必要がありますが、これは今のところこのユニークな状況の解決策のようです。

with points as (
   select p.id, p.geom from point p inner join zipcode z
   on p.zipcode = z.zipcode
   where county = 24
   ) 


SELECT count(points.id)
FROM points
WHERE ST_DWITHIN(points.geom, (ST_SetSRID(ST_Point(-121.479756008715,38.563236291512),4269)), 16090.0, false)

1
3つのクエリプランすべてとテーブルのスキーマ(回答\ dポイントで要求された)を確認する必要があります。
エヴァンキャロル

0

にインデックスを作成するzipcode(county, zipcode)必要があります。これにより、zでのみスキャンするインデックスが提供されます。

またbtree_gistpoint(zipcode, geom)インデックスまたはpoint(geom, zipcode)and zipcode(zipcode, county)インデックスを作成する拡張機能を試すこともできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.