mysql中的ST_Distance_Sphere没有给出两个位置之间的准确距离
Posted
技术标签:
【中文标题】mysql中的ST_Distance_Sphere没有给出两个位置之间的准确距离【英文标题】:ST_Distance_Sphere in mysql not giving accurate distance between two locations 【发布时间】:2016-06-26 16:14:18 【问题描述】:我的requirement
是使用mysql 在给定map 上计算两个locations
之间的distance
。我在mysql 中找到了一个名为ST_Distance_Sphere 的函数,它返回一个球体上两个位置和/或多个位置之间的最小球面距离(以米为单位)。
当我使用ST_Distance_Sphere 和lat_lng_distance
函数计算两个位置之间的距离时,我发现ST_Distance_Sphere 给出的距离与lat_lng_distance
函数的距离不同。
我的lat_lng_distance
功能码如下
CREATE FUNCTION `lat_lng_distance` (lat1 FLOAT, lng1 FLOAT, lat2 FLOAT, lng2 FLOAT)
RETURNS FLOAT
DETERMINISTIC
BEGIN
RETURN 6371 * 2 * ASIN(SQRT(
POWER(SIN((lat1 - abs(lat2)) * pi()/180 / 2),
2) + COS(lat1 * pi()/180 ) * COS(abs(lat2) *
pi()/180) * POWER(SIN((lng1 - lng2) *
pi()/180 / 2), 2) ));
END
传递给ST_Distance_Sphere和lat_lng_distance
函数的两个位置((38.898556,-77.037852),(38.897147,-77.043934))
如下
SET @pt1 = ST_GeomFromText('POINT (38.898556 -77.037852)');
SET @pt2 = ST_GeomFromText('POINT (38.897147 -77.043934 )');
SELECT ST_Distance_Sphere(@pt1, @pt2)/1000,lat_lng_distance(38.898556,-77.037852,38.897147,-77.043934 );
得到的结果如下
我在google maps上查看了两个位置之间的距离,发现lat_lng_distance
与两个位置之间的实际距离很接近。有人可以告诉我为什么ST_Distance_Sphere 没有给出两个位置之间的准确距离吗?
【问题讨论】:
【参考方案1】:ST_DISTANCE_SPHERE 要求将点表示为POINT(longitude, latitude)
,您在代码中将它们颠倒了
set @lat1 = 38.898556;
set @lon1 = -77.037852;
set @lat2 = 38.897147;
set @lon2 = -77.043934;
SET @pt1 = point(@lon1, @lat1);
SET @pt2 = point(@lon2, @lat2);
SELECT ST_Distance_Sphere(@pt1, @pt2)/1000,
lat_lng_distance(@lat1,@lon1,@lat2,@lon2);
+-------------------------------------+-------------------------------------------+
| ST_Distance_Sphere(@pt1, @pt2)/1000 | lat_lng_distance(@lat1,@lon1,@lat2,@lon2) |
+-------------------------------------+-------------------------------------------+
| 0.549154584458455 | 0.5496311783790588 |
+-------------------------------------+-------------------------------------------+
这会得到更接近函数返回值的结果。
【讨论】:
谢谢没有注意到我的错误【参考方案2】:首先,您不能使用默认的 SRID 0 来进行任何计算。当您使用文本函数中的几何图形时,您必须提供 4326(SRID 即度数),因为这是您的输入格式。 MYSQL 可能不关心它,但它应该这样做,因为每个严肃的 GIS 数据库都关心并要求指定输入 SRID。
第二个经度是 X,纬度是 Y(不是其他方式)
SET @pt1 = ST_GeomFromText('POINT (-77.037852 38.898556 )', 4326);
SET @pt2 = ST_GeomFromText('POINT (-77.043934 38.897147 )',4326);
最后但并非最不重要的一点是,当您计算距离时,您必须将坐标转换为您所在地区可用的本地最精确的 SRID。
例如,SRID 2877 用于美国(根据您所在的坐标)。
MYSQL ST_Distance_Sphere 函数不关心输入 SRID 并且总是以米为单位返回结果。
但这通常是不正确的,所有其他数据库都使用适用于它的指定 SRID 度量单位。
Bellow 我正在尝试做正确的事情并将 SRID 转换为 2877,如果我们将所有内容都保留为 4326(谷歌墨卡托),即使 MYSQL 也会以相同的方式工作。
对于 2877,PostGRES 将以英尺为单位返回相同查询的结果,但 MYSQL 仍然返回米。所以输出除以 1609,我们得到了大约 0.34 英里的正确结果。这是一个正确的值,因为使用不同的方法测试过
SELECT ST_Distance_Sphere(ST_GeomFromText(ST_AsText(@pt1),2877), ST_GeomFromText(ST_AsText(@pt2),2877))/1609.344;
【讨论】:
【参考方案3】:致所有使用 MYSQL 8 的人:
对于所有 mysql 地理定位功能,必须使用正确的 SRID,否则您将无法获得正确的结果。
最常用的是 SRID 4326(GPS 坐标、Google 地球)和 SRID 3857(用于 Google 地图、OpenStreetMap 和大多数其他网络地图)。
两点之间的正确距离计算示例:
SELECT ST_Distance(ST_GeomFromText('POINT(51.513 -0.08)', 4326), ST_GeomFromText('POINT(37.745 -122.4383)', 4326)) / 1000 AS km;
下面是对这个话题的一个很好的解释: https://medium.com/maatwebsite/the-best-way-to-locate-in-mysql-8-e47a59892443
mysqlserverteam 有一些很好的解释:https://mysqlserverteam.com/spatial-reference-systems-in-mysql-8-0/ https://mysqlserverteam.com/geography-in-mysql-8-0/
【讨论】:
【参考方案4】:顺便说一句,MySQL 在内部使用一个晦涩且过时的常量来实现这一点。所以这真的取决于你对准确的定义。
ST_Distance_Sphere
因此,从本质上讲,MySQL 中的半径是从 PostGIS 的一个惰性复制作业中提取的,该作业将半径从英里转换为米,从一个随机的 20 年前的 PostgreSQL 模块中的一个不起眼的常数。
【讨论】:
以上是关于mysql中的ST_Distance_Sphere没有给出两个位置之间的准确距离的主要内容,如果未能解决你的问题,请参考以下文章
在 MySQL 8 中使用点数据类型和 st_distance_sphere 查找最近的地方
ST_Distance_Spheroid 的 MySQL GeoSpatial 函数?返回 GLength 类型中使用的度量标准?