&_よりst_intersectsの方が速い理由


10

ポイントの表です。〜1Mレコード

SELECT COUNT(*) as value FROM alasarr_social_mv s; 
Output: 976270

st_intersectsは空間インデックスを強制的に使用するように見えますが、&&は使用しません。

使用例ST_Intersects(282ms)

SELECT COUNT(*) as value
FROM alasarr_social_mv 
WHERE ST_Intersects(
  the_geom_webmercator, 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)
)


Aggregate  (cost=34370.18..34370.19 rows=1 width=0) (actual time=282.715..282.715 rows=1 loops=1)
  ->  Bitmap Heap Scan on alasarr_social_mv s  (cost=5572.17..34339.84 rows=60683 width=0) (actual time=21.574..240.195 rows=178010 loops=1)
        Recheck Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Filter: _st_intersects(the_geom_webmercator, '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Heap Blocks: exact=4848
        ->  Bitmap Index Scan on alasarr_social_mv_gix  (cost=0.00..5569.13 rows=182050 width=0) (actual time=20.836..20.836 rows=178010 loops=1)
              Index Cond: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
Planning time: 0.192 ms
Execution time: 282.758 ms

&&(414ms)を使用したサンプル

SELECT COUNT(*) as value
FROM alasarr_social_mv  
WHERE the_geom_webmercator && 
  ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857)

Aggregate  (cost=22535.97..22535.97 rows=1 width=0) (actual time=414.314..414.314 rows=1 loops=1)
  ->  Seq Scan on alasarr_social_mv  (cost=0.00..22444.94 rows=182050 width=0) (actual time=0.017..378.427 rows=178010 loops=1)
        Filter: (the_geom_webmercator && '0103000020110F0000010000000500000000000000441519C1000000002BC5524100000000441519C1000000C069CB524100000000048E18C1000000C069CB524100000000048E18C1000000002BC5524100000000441519C1000000002BC55241'::geometry)
        Rows Removed by Filter: 798260
Planning time: 0.134 ms
Execution time: 414.343 ms

PostGISバージョン

POSTGIS="2.2.2" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.0, released 2014/04/16" LIBXML="2.7.8" LIBJSON="UNKNOWN" (core procs from "2.2.2" need upgrade) RASTER (raster procs from "2.2.2" need upgrade)  alasarr 2 mins ago

2
テキストのスクリーンショットを質問に貼り付けないでください。それらをコードとしてコピーして貼り付けることはできますか?私はあなたを助けるためにそれらを読むことができません。
エヴァンキャロル

できました。私はもう少し良くなっていると思います
alasarr 2017

私はあなたの新しいクエリプランをそれに移植しようとしました。プランを自由にアップグレードしてもかまいませんが、スタイルを維持してください。
エヴァンキャロル

4
この質問を見てください。&&演算子は実際に境界ボックスクエリを実行しますが、ST_Intersectsは境界ボックスクエリを使用して、実際の比較をテストするジオメトリを決定します。したがって、&&の方が高速です。ただし、&&の右側にST_MakeEnvelopeを使用すると、クエリプランナーが何らかの理由で全テーブルスキャンを選択するようになる可能性があります(説明から明らかです)。まずCTEでジオメトリを作成して、オプティマイザを「だます」ことができるかどうかを確認してください。
ジョンパウエル

あなたが正しい!CTE内で機能します
alasarr 2017

回答:


16

この種の発見はかなり頻繁に出てきます、そしてそれは少しあいまいなので、再言する価値があります。ST_Intersectsや&&(ST_Intersectsが内部で使用する)など、それを使用する関数内でジオメトリを定義する場合、「それ」はジオメトリ作成の結果を認識しないため、クエリプランナーはフルテーブルスキャンを選択します。関数、つまりこの場合はST_MakeEnvelopeです。CTEで交差をチェックするジオメトリを定義する場合、オプティマイザは既知の数量を処理しており、可能な場合は空間インデックスを使用します。

したがって、クエリを次のように書き換えます。

WITH test_geom (geom) AS 
   (SELECT ST_MakeEnvelope(-410961,4920492,-402305,4926887,3857))
  SELECT COUNT(*) as value
    FROM alasarr_social_mv mv, test_geom tg 
   WHERE ST_Intersects(mv.the_geom_webmercator, tg.geom)

空間インデックスを使用します。同様に、&&はインデックスを使用して境界ボックスをチェックするようになり、(データに対してテストすることはできませんが)ST_Intersectsよりも高速になるはずです。

興味深いことに、クエリでは、ST_Intersectsはビットマップスキャン(要旨ではない)インデックスを使用していますが、&&はインデックスを使用していません。したがって、両方のクエリはCTEでより高速になりますが、&&はST_Intersectsよりも高速になるはずです。

この質問とその回答/コメントで何が起こっているかについての詳細な説明があります

EDIT:あなたがST_Intersectsはの定義を見れば、これを明示的にするためにpostgis.sql(によって呼び出されるCREATE EXTENSION postgisと、あなたのPostgresのcontribディレクトリにインストールした)、あなたが表示されます。

---- Inlines index magic
CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
    RETURNS boolean
    AS 'SELECT $1 OPERATOR(&&) $2 AND _ST_Intersects($1,$2)'
    LANGUAGE 'sql' IMMUTABLE ;

コメントを含む:インデックスマジックをインライン化します。


1
ST_Intersectsが内部で&&を使用しているとは思いません。
エヴァンキャロル

4
@EvanCarroll、私の編集を確認してください。関数が定義されているpostgis.sqlを見てください。
ジョンパウエル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.