当前位置: 首页 > 知识库问答 >
问题:

ST_DWithin不使用带有非文字参数的索引

夏宪
2023-03-14

我在AmazonRDS上使用PostResql9.3w/PostGIS 2.1.8。我有一个名为project_location的表,它定义了“地理Geofence”(每个Geofence本质上都是一个坐标和半径)。地理Geofence使用名为“位置”的几何图形列和名为“半径”的双列存储。我在location列上有一个空间索引。

CREATE TABLE project_location
(
  ...
  location geography(Point,4326),
  radius double precision NOT NULL,
  ...
)
CREATE INDEX gix_project_location_location 
ON project_location USING gist (location);

该表目前约有50,000条记录。如果我查询表格来查找地理Geofence包含点的所有project_locations,类似于

SELECT COUNT(*) 
FROM project_location 
WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(-84.1000, 34.0000),4326)::geography, radius);

我发现没有使用空间索引。EXPLAIN的结果显示如下:

"Aggregate  (cost=11651.97..11651.98 rows=1 width=0)"
"  ->  Seq Scan on project_location  (cost=0.00..11651.97 rows=1 width=0)"
"        Filter: ((location && _st_expand('0101000020E610000066666666660655C00000000000004140'::geography, radius)) AND ('0101000020E610000066666666660655C00000000000004140'::geography && _st_expand(location, radius)) AND _st_dwithin(location, '0101000020E610000066666666660655C00000000000004140'::geography, radius, true))"

但是,如果半径是一个常量值,如下所示

SELECT COUNT(*) 
FROM project_location 
WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(-84.1000, 34.0000),4326)::geography, 1000);

空间索引如EXPLAIN所示

"Aggregate  (cost=8.55..8.56 rows=1 width=0)"
"  ->  Index Scan using gix_project_location_location on project_location  (cost=0.28..8.55 rows=1 width=0)"
"        Index Cond: (location && '0101000020E610000066666666660655C00000000000004140'::geography)"
"        Filter: (('0101000020E610000066666666660655C00000000000004140'::geography && _st_expand(location, 1000::double precision)) AND _st_dwithin(location, '0101000020E610000066666666660655C00000000000004140'::geography, 1000::double precision, true))"

读过ST_DWithin如何使用索引后,我理解了为什么会出现这种情况。基本上,基于半径的边界框用于“预过滤”候选点,以在对这些点进行相对昂贵的距离计算之前确定可能的匹配。

我的问题是有什么方法可以进行这种类型的搜索,以便使用空间索引?基本上是一种查询带有一堆可变半径地理Geofence的表的方法?

共有1个答案

李永寿
2023-03-14

PostGIS允许通过使用功能索引来加快查询速度。我不知道如何在地理数据类型中进行查询,因为那里没有ST_展开,但是如果您将数据存储在某个墨卡托投影中(例如,SRID=3857),查询将非常简单。

想法:

  • 生成一个方框,在你的点周围以半径为单位展开;
  • 在这些盒子上建立索引;
  • 针对这些框查询用户点;
  • 通过精确的半径重新检查。

在您的project_location表上:

create index on project_location using gist (ST_Expand(location, radius));

现在,您可以使用ST_Expand(位置,半径),就像它是索引的几何列一样。

select count(*) from project_location where ST_Intersects(ST_Expand(location, radius), <your_point>) and ST_Distance(location, <your_point>) < radius;

现在您跳过了ST_DWithin,因为您希望重新检查永远不要尝试使用索引,而是在几何函数上使用索引。

对于地理,您可以尝试使用ST_Envelope(ST_Buffer(geom,半径))存根ST_Expand。

 类似资料:
  • 问题内容: 渲染时捕获到异常: 找不到带有参数’()’和关键字参数’{}’的’products.views.’filter_by_led’。 我能够从shell成功导入,并且可以正常工作,因此路径应该正确。 这是urls.py: 这是生成错误的地方: 我不明白,因为这可以在同一个文件中正常工作: 这是函数定义: 我不明白为什么Django会认为该函数无法为该函数找到Reverse。 我删除了所有文

  • 我正试图使用阿拉莫菲尔上传文件。使用文件()时,上传效果很好,但是,我似乎不知道如何使用选项? 这是我的测试: 我的状态代码是415? 此外,如何在上传中发送其他参数? 谢啦 编辑 我没有设置正确的内容类型: 仍然不知道如何发送附加参数随上传。

  • 我们使用SQL Server数据库。当试图使用27GB内存在具有100M条记录的表上运行查询时,Hibernate会将查询(无论是

  • 是否有可能将方法引用与参数一起使用?我喜欢流的想法,我只是想让代码更易读。 实际上,我认为有一个类似的问题,方法引用了一个参数,我读了,但不知道如何在我的代码中使用bind2方法。这是唯一的解决办法吗?

  • 问题内容: 我有这样的网址格式: 它在浏览器中可以正常工作,但是当我在外壳中执行此操作时,可以进行测试: 我感到恐惧: 我在这里想念什么? 问题答案: 你必须指定

  • 我有一个页面,在那里我可以得到一个条目列表。现在,我希望能够从这些列表中进行搜索。 我当前检索列表的url是/show/products。我想在此页面中添加一个搜索表单,以便可以使用请求参数进行搜索。是的,我可以使用ajax,但我必须使用请求参数。 所以如果我搜索一个产品名称,那么- /show/products?##########################################