PostGIS,索引相交生成的地理
PostGIS, Indexed Intersecting Generated Geography
好的,我想我遇到了一个奇怪的问题,而且我一直在寻找答案。
我要开始了:
我有 table 台设备:
Column | Type | Modifiers
----------+-----------+------------------------------------------------------
id | integer | not null default nextval('devices_id_seq'::regclass)
location | geography |
radius | integer |
表示一组设备的位置和位置分辨率。
我想查找区域范围内的设备。
所以,我可以这样查询:
SELECT count(id) FROM devices WHERE ST_intersects(ST_buffer(ST_GeographyFromText('POINT(-80.519142 43.460270)'), 20000), ST_buffer(location, radius));
硬编码位置最终将来自连接。
所以,我有不确定的设备和一个大区域,我想知道哪些设备可能在该区域内。
此查询有效,但在 100000 台设备的测试中,需要 28 秒。
所以我想索引它。
一整天了,我知道一些事情,但没有正确答案。
首先,做一个像 CREATE INDEX device_buffer ON devices USING gist (st_buffer(location, radius));
这样的索引似乎是存在的,但是看看上面的查询,它实际上从未被使用过。
看explain的输出,显示geography(st_transform(st_buffer(st_transform(geometry(location), _st_bestsrid(location, location)), (radius)::double precision), 4326))
,好像是扩展版的
为其添加索引似乎也无济于事。
所以,为了弄清楚是 ST_INTERSECT
还是我出了问题,我做了:
CREATE MATERIALIZED VIEW device_buffer_view AS SELECT id, ST_BUFFER(location, radius) as buffer FROM devices;
并在该视图的缓冲区字段上放置一个索引。
该查询命中索引。
好的。
这告诉我,我的缓冲区可以在交叉点中建立索引。
不过,这仍然不是很好,因为我实际上并不想要实体化视图。
不过,我想要 table 中的位置和半径,因为应用程序的其他部分会查看此数据,并允许稍后对其进行调整。仅存储生成的地理位置没有帮助。
根据我在网上找到的东西,我试过:
CREATE FUNCTION geog(rec devices) RETURNS geography IMMUTABLE LANGUAGE SQL AS 'SELECT ST_BUFFER(.location, .radius);';
这允许我做 SELECT devices.geog FROM devices
,并为其编制索引,但要放置一个索引,例如:
CREATE INDEX device_geog ON devices USING GIST ((devices.geog));
在 select 查询中使用 devices.geog
时效果并没有更好。
所以,看来我可能必须将地理位置存储在 table 中,这很好,然后我可以对其进行索引。
不过,我不希望它被非规范化。
我试图制定一个规则,这样如果位置或半径有更新,它会自动重新计算存储的地理信息,但它抱怨递归规则...
那么,是否有一些非常简单的东西我没有触及,或者我错过了一些微妙的地方?
我很困惑,有点沮丧,甚至可能超出了我的理解范围。
有什么想法吗?
这不是什么奇怪的问题。使用缓冲区作为邻近搜索对于新用户来说是一个非常常见的错误。它要慢得多,不使用空间索引,而且不太精确(因为缓冲区通常每季度有 16 个段)。按半径缓冲特征在视觉上很直观,但对于邻近搜索来说计算量太大。
要使查询更可靠、更快,请使用 ST_DWithin。此函数查找在其他要素的指定距离内的要素。它还将使用 GiST 空间索引。
SELECT count(id)
FROM devices
WHERE ST_DWithin(location, ST_MakePoint(-80.519142, 43.460270)::geography, radius);
如果您需要以降低精度为代价提高速度,请使用球形距离而不是椭球体,方法是将 use_spheroid=false
添加到邻近过滤器。
好的,我想我遇到了一个奇怪的问题,而且我一直在寻找答案。
我要开始了:
我有 table 台设备:
Column | Type | Modifiers
----------+-----------+------------------------------------------------------
id | integer | not null default nextval('devices_id_seq'::regclass)
location | geography |
radius | integer |
表示一组设备的位置和位置分辨率。
我想查找区域范围内的设备。
所以,我可以这样查询:
SELECT count(id) FROM devices WHERE ST_intersects(ST_buffer(ST_GeographyFromText('POINT(-80.519142 43.460270)'), 20000), ST_buffer(location, radius));
硬编码位置最终将来自连接。
所以,我有不确定的设备和一个大区域,我想知道哪些设备可能在该区域内。 此查询有效,但在 100000 台设备的测试中,需要 28 秒。
所以我想索引它。 一整天了,我知道一些事情,但没有正确答案。
首先,做一个像 CREATE INDEX device_buffer ON devices USING gist (st_buffer(location, radius));
这样的索引似乎是存在的,但是看看上面的查询,它实际上从未被使用过。
看explain的输出,显示geography(st_transform(st_buffer(st_transform(geometry(location), _st_bestsrid(location, location)), (radius)::double precision), 4326))
,好像是扩展版的
为其添加索引似乎也无济于事。
所以,为了弄清楚是 ST_INTERSECT
还是我出了问题,我做了:
CREATE MATERIALIZED VIEW device_buffer_view AS SELECT id, ST_BUFFER(location, radius) as buffer FROM devices;
并在该视图的缓冲区字段上放置一个索引。 该查询命中索引。 好的。 这告诉我,我的缓冲区可以在交叉点中建立索引。
不过,这仍然不是很好,因为我实际上并不想要实体化视图。
不过,我想要 table 中的位置和半径,因为应用程序的其他部分会查看此数据,并允许稍后对其进行调整。仅存储生成的地理位置没有帮助。
根据我在网上找到的东西,我试过:
CREATE FUNCTION geog(rec devices) RETURNS geography IMMUTABLE LANGUAGE SQL AS 'SELECT ST_BUFFER(.location, .radius);';
这允许我做 SELECT devices.geog FROM devices
,并为其编制索引,但要放置一个索引,例如:
CREATE INDEX device_geog ON devices USING GIST ((devices.geog));
在 select 查询中使用 devices.geog
时效果并没有更好。
所以,看来我可能必须将地理位置存储在 table 中,这很好,然后我可以对其进行索引。
不过,我不希望它被非规范化。
我试图制定一个规则,这样如果位置或半径有更新,它会自动重新计算存储的地理信息,但它抱怨递归规则...
那么,是否有一些非常简单的东西我没有触及,或者我错过了一些微妙的地方?
我很困惑,有点沮丧,甚至可能超出了我的理解范围。
有什么想法吗?
这不是什么奇怪的问题。使用缓冲区作为邻近搜索对于新用户来说是一个非常常见的错误。它要慢得多,不使用空间索引,而且不太精确(因为缓冲区通常每季度有 16 个段)。按半径缓冲特征在视觉上很直观,但对于邻近搜索来说计算量太大。
要使查询更可靠、更快,请使用 ST_DWithin。此函数查找在其他要素的指定距离内的要素。它还将使用 GiST 空间索引。
SELECT count(id)
FROM devices
WHERE ST_DWithin(location, ST_MakePoint(-80.519142, 43.460270)::geography, radius);
如果您需要以降低精度为代价提高速度,请使用球形距离而不是椭球体,方法是将 use_spheroid=false
添加到邻近过滤器。