
在处理地理空间数据时,我们经常需要找出某个点附近的其他点,并按距离远近进行排序。例如,给定一个参考点 (mypointlat, mypointlng),我们希望从 point 表中查询出所有距离该参考点在 metres 范围内的点,并按照它们与参考点的实际距离(或距离的平方)进行升序排列。
最初的查询可能只关注筛选功能,例如使用勾股定理计算距离的平方来判断点是否在指定范围内:
SELECT *
FROM point l
WHERE (
(ABS(l.lat * 111139 - myPointLat * 111139)^2) +
(ABS(l.lng * 111139 - (myPointLng * 111139))^2)
) <= metres^2;这里的 111139 是一个近似的系数,用于将经纬度(度)转换为米,以便进行距离计算。ABS(...) ^ 2 实际上是计算了经度差和纬度差的平方,然后求和,得到的是距离的平方。现在,我们的目标是如何基于这个计算出的距离平方值进行排序。
为了避免在 WHERE 和 ORDER BY 子句中重复复杂的距离计算表达式,我们可以将距离计算封装在一个子查询或公共表表达式(CTE)中,作为一个新的计算列。这样可以提高代码的可读性和维护性。
示例代码(使用子查询):
SELECT Column1, Column2, Column3 -- 选择你需要的列
FROM (
SELECT
*, -- 或者列出所有需要的原始列
(
(ABS(l.lat * 111139 - myPointLat * 111139)^2) +
(ABS(l.lng * 111139 - (myPointLng * 111139))^2)
) AS proximity_squared -- 将距离的平方命名为 proximity_squared
FROM point l
) AS subquery_points
WHERE proximity_squared <= metres^2
ORDER BY proximity_squared;说明:
这种方法的优点是代码更加清晰,避免了重复冗长的计算表达式。
尽管子查询方法提高了代码的可读性,但在某些情况下,尤其是在处理大型数据集时,重复距离计算表达式可能会带来更好的性能。这是因为PostgreSQL查询优化器在执行 WHERE 子句时,可以先过滤掉不符合条件的行,从而显著减少需要进行 ORDER BY 操作的数据集大小。
当表达式在 WHERE 和 ORDER BY 中重复时,优化器通常能够更好地理解查询意图,并可能在过滤阶段就完成计算,避免对整个表进行不必要的排序。
示例代码(重复表达式):
SELECT *
FROM point l
WHERE (
(ABS(l.lat * 111139 - myPointLat * 111139)^2) +
(ABS(l.lng * 111139 - (myPointLng * 111139))^2)
) <= metres^2
ORDER BY (
(ABS(l.lat * 111139 - myPointLat * 111139)^2) +
(ABS(l.lng * 111139 - (myPointLng * 111139))^2)
);说明:
在PostgreSQL中,当需要根据计算出的距离(例如使用勾股定理)对结果进行筛选并排序时,主要有两种策略:
选择哪种方法取决于你的具体需求,包括代码维护性要求、数据集大小以及对查询性能的敏感度。在实际部署前,建议对两种方法进行性能测试(使用 EXPLAIN ANALYZE),以确定最适合你应用场景的方案。
以上就是PostgreSQL中按勾股定理计算的距离进行高效排序的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号