为什么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)'17

我试图将您的新查询计划移植到其中。随意升级计划,但尝试保留样式。
埃文·卡罗尔

4
看看这个问题。&&运算符实际上是在执行边界框查询,而ST_Intersects使用边界框查询来确定要测试哪些几何以进行实际比较-因此您希望&&更快。但是,很可能由于&&右边的ST_MakeEnvelope的使用,使得查询计划者出于某种原因选择了全表扫描(从说明中可以明显看出)。尝试先在CTE中创建几何,然后看看是否可以“愚弄”优化器。
约翰·鲍威尔

你是对的!它在CTE内部工作
阿拉尔(Alasarr)'17

Answers:


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更快。

有关此问题及其答案/评论的更多解释。

编辑:为了使这一点明确,如果您查看postgis.sql(由CREATE EXTENSION postgisPostgres安装的contrib目录中调用并在其中找到的)中ST_Intersects的定义,您将看到:

---- 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,它应该更清晰。
约翰·鲍威尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.