优化 postgis 查询 - 为什么不使用第二个索引?

Optimizing a postgis query - why is 2nd index not being used?

我们有一个包含数千万个多边形的 table,我们有这个索引:

CREATE INDEX IF NOT EXISTS polygons_geog_idx ON polygons USING GIST(geog);

这让我们可以真正高效地查询数据库,如下所示:

SELECT * FROM polygons WHERE st_dwithin('SRID=4326;POINT(-1 50)'::geography, geog, 500);

现在由于业务需要,我们只需要return最大的200个多边形。像这样很容易做到:

完整查询: SELECT gid, st_area(geog) as size FROM polygons WHERE st_dwithin(geog, 'SRID=4326;POINT(-1 50)'::geography, 500) ORDER BY st_area(geog) DESC LIMIT 200.

由于 order byselect 我们的查询速度降低了 10 倍。我认为通过添加另一个索引可以很容易地解决这个问题 : CREATE INDEX polygons_geog_area_idx ON polygons (st_area(geog));

但是polygons_geog_area_idx好像没有捡到:

Sort  (cost=8.23..8.23 rows=1 width=12) (actual time=133.755..142.427 rows=2325 loops=1)
  Sort Key: (st_area(geog, true))
  Sort Method: quicksort  Memory: 205kB
  ->  Index Scan using polygons_geog_idx on polygons  (cost=0.14..8.22 rows=1 width=12) (actual time=0.468..121.974 rows=2325 loops=1)
        Index Cond: (geog && '0101000020E6100000C33126587787F1BF3B0D62B197654940'::geography)
        Filter: (('0101000020E6100000C33126587787F1BF3B0D62B197654940'::geography && _st_expand(geog, '500'::double precision)) AND _st_dwithin(geog, '0101000020E6100000C33126587787F1BF3B0D62B197654940'::geography, '500'::double precision, true))
        Rows Removed by Filter: 3
Planning Time: 0.157 ms
Execution Time: 151.196 ms

(注意:这是在开发数据集上,比实际数据集小得多,稍后将 运行)

我错过了什么?你能像我想要的那样使用 2 个索引吗?

PostgreSQL不能这样合并两个索引,一个是顺序,一个是选择性。

要按面积排序,首先需要计算面积。排序本身很快(只用了 15% 的时间)所以一定是面积的计算很慢。 EXPLAIN VERBOSE 向我建议面积的计算是作为索引扫描的一部分完成的,然后将结果传递给排序,而不是在排序本身中完成。因此,将执行此操作的时间归因于索引扫描是有道理的。

要缩短计算面积所需的时间,您可以将其计算并存储为 table 的一部分。最好的方法(使用足够新的版本)是使用生成的列。

alter table polygons add polygon_area double precision generated always as (st_area(geog)) stored;