St_intersects neden && 'den daha hızlı?


10

Bu bir puan tablosu. ~ 1 milyon kayıt

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

Görünüşe göre st_intersects kuvvetleri uzamsal dizinleri kullanıyor ama && kullanmıyor.

Örnek kullanarak ST_Intersects(282 ms)

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

Örnek kullanarak &&(414 ms)

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 sürümü

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
Metnin ekran görüntülerini soruya yapıştırmayın. Bunları kod olarak kopyalayıp yapıştırabilir misiniz? Sana yardım etmek için okuyamıyorum.
Evan Carroll

Bitti. Sanırım şimdi biraz daha iyi
alasarr

Yeni sorgu planlarınızı buna aktarmaya çalıştım. Planları yükseltmekten çekinmeyin, ancak stili korumaya çalışın.
Evan Carroll

4
Bu soruya bir göz atın . && operatörü aslında bir sınırlayıcı kutu sorgusu gerçekleştirirken, ST_Intersects, gerçek karşılaştırma için hangi geometrileri test edeceğini belirlemek için bir sınırlayıcı kutu sorgusu kullanır - böylece && daha hızlı olmasını beklersiniz. Bununla birlikte, && sağında ST_MakeEnvelope kullanımının sorgu planlayıcıyı bir nedenden ötürü tam bir tablo taraması yapması muhtemeldir (açıklamasından da anlaşılacağı gibi). İlk önce bir CTE'de geometri oluşturmayı deneyin ve optimize ediciyi "kandırabilir misiniz" diye bakın.
John Powell

Haklısın! bir CTE içinde çalışır
alasarr

Yanıtlar:


16

Bu tür bir bulgu oldukça sık görülür ve biraz belirsizdir, bu yüzden yeniden düzenlemeye değer. ST_Intersects veya && (ST_Intersects'in başlık altında kullandığı) gibi onu kullanan bir işlev içinde bir geometri tanımlarsanız, sorgu planlayıcısı tam bir tablo taraması seçer; işlevi, yani, bu durumda ST_MakeEnvelope .. Eğer bir CTE'de kesişim olup olmadığını kontrol etmek istediğiniz geometriyi tanımlarsanız, optimize edici bilinen bir miktarla ilgilenir ve varsa uzamsal bir dizin kullanır.

Bu nedenle, sorgunuzu şu şekilde yeniden yazın:

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)

artık bir uzamsal dizin kullanacak. Benzer şekilde, && artık sınırlayıcı bir kutu olup olmadığını kontrol etmek için bir dizin kullanacak ve (verilerinize karşı test edememe rağmen) ST_Intersects'ten daha hızlı olmalıdır.

İlginç bir şekilde, sorgunuzda ST_Intersects bir bitmap tarama (gist değil) dizini kullanırken && hiçbir dizin kullanmıyor. Dolayısıyla, her iki sorgu da CTE ile daha hızlı olacaktır, ancak && artık ST_Intersects'ten daha hızlı olmalıdır.

Bu soruda neler olduğu ve cevapları / yorumları hakkında daha fazla açıklama var .

DÜZENLEME : Bunu açıkça belirtmek için postgis.sql dosyasında ( CREATE EXTENSION postgisPostgres kurulumunuzun katkıda bulunan dizininde denir ve bulunur) ST_Intersects tanımına bakarsanız şunu göreceksiniz:

---- 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 ;

yorum dahil: dizin sihir satır içi.


1
ST_Intersects'in başlık altında && kullandığını düşünmüyorum.
Evan Carroll

4
@EvanCarroll, düzenlememi kontrol et. İşlevlerin tanımlandığı postgis.sql dosyasına bir göz atın ve daha net olması gerekir.
John Powell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.