postgresql - PostGIS 将地理列上的 st_dwithin 转换为 && 而不保留自定义空间参考系统
问题描述
当我在具有 GIST 索引的地理列上使用 st_dwithin 时,解释计划显示索引扫描的缩小条件变为 && 条件。在这种不同的情况下,如果在没有索引的情况下使用全表扫描执行 st_dwithin,则结果集会丢失包含的行。
没有索引的解释计划中的条件是
st_dwithin(
geog,
'010100002010A4000000000000006066400000000000000000'::geography,
'3'::double precision,
false
)
但是解释计划表明,当列有 GIST 索引时,它变为以下
geog && _st_expand(
'010100002010A4000000000000006066400000000000000000'::geography,
'3'::double precision
)
geography 列具有自定义空间参考系统,在转换为 && 条件时未保留该参考系统。自定义空间参考系统是一个球体,其半径为 1 度等于 1 米的大圆距离。所以 (0 0) 的一点距离 (0 1) 有一个距离。
设置代码如下
-- Insert the custom spatial reference system into the db.
insert into spatial_ref_sys values (42000, 'customsrs', 1,
'GEOGCS[
"Normal Sphere (r=57.2957795)",
DATUM["unknown",
SPHEROID["Sphere",57.29577951308232087679,0]
],
PRIMEM["Greenwich",0],
CS[ellipsoidal,2],
AXIS["latitude",north],
AXIS["longitude",east],
UNIT["degree",0.0174532925199433]
]', '+proj=longlat +ellps=sphere +R=57.29577951308232087679 +no_defs');
-- Create a new table with a geography column in the new spatial reference system.
CREATE TABLE geographytest(gid serial PRIMARY KEY, geog geography(POINT, 42000));
-- Insert some data around the dateline
insert into geographytest (gid, geog) values
(1, 'srid=42000;POINT(179 0)'),
(2, 'srid=42000;POINT(178 0)'),
(3, 'srid=42000;POINT(-179 0)'),
(4, 'srid=42000;POINT(-179 90)'),
(5, 'srid=42000;POINT(0 0)');
-- Select all points within a distance of 3 from POINT(179 0).
-- The expected 3 points are returned, with st_distances of 0, 1 and 2.
select
gid,
st_distance(
geog,
'srid=42000;POINT(179 0)',
false
),
st_dwithin(
geog,
'srid=42000;POINT(179 0)',
3,
false
)
from
geographytest
where
st_dwithin(
geog,
st_geogfromtext('srid=42000;POINT(179 0)'),
3,
false
);
-- Create a GIST index on our geography column
CREATE INDEX geographytestindex ON geographytest USING gist (geog);
VACUUM analyze geographytest (geog);
-- Now select again using the same query.
-- Now only one result is returned, the row that has POINT(179 0).
-- The explain plan indicates that the index scan is using
-- Index Cond: (geog && _st_expand('010100002010A4000000000000006066400000000000000000'::geography, '3'::double precision))
-- when performing the select.
select
gid,
st_distance(
geog,
'srid=42000;POINT(179 0)',
false
),
st_dwithin(
geog,
'srid=42000;POINT(179 0)',
3,
false
)
from
geographytest
where
st_dwithin(
geog,
st_geogfromtext('srid=42000;POINT(179 0)'),
3,
false
);
将 st_dwithin 距离增加到 230000 而不是 3 会返回所有三个预期的行,因为这是它们在 srid 4326 中的距离。
当列上存在索引时,如何让 PostGIS 在查询中使用我的自定义空间参考系统?
解决方案
问题在于_st_expand
. 此函数扩展给定地理的边界框。查看代码,我们可以看到使用WGS84半径修改了所需的距离,因此确实忽略了自定义CRS。如果您愿意,可以报告错误。
/* Read our distance value and normalize to unit-sphere. */
distance = PG_GETARG_FLOAT8(1);
/* Magic 1% expansion is to bridge difference between potential */
/* spheroidal input distance and fact that expanded box filter is */
/* calculated on sphere */
unit_distance = 1.01 * distance / WGS84_RADIUS;
推荐阅读
- next.js - 无法将 Next.js 部署到 Netlify。由于@netlify/plugin-nextjs 插件中的错误,部署失败
- python - Python路径问题:预期的字符串但找到:'r'
- php - cURL + PHP - Trello 卡片中的附件
- r - R:按重复数字的数字列对数据框进行排序
- javascript - Vanilla Javascript 组件在另一个组件中不起作用
- python - 是否有可能使这个 python 乌龟图像代码更短?
- javascript - 无法使用 three.js 渲染 GLTF 对象
- javascript - 无法在媒体查询中隐藏溢出-x
- excel - 在时间轴上向右移动 10 行的组,直到它们都 = 零分,需要优化
- android - 通过 ADB 启用/禁用无线电源共享 (Galaxy S20)