mysql - 如何在不使用几何类型的情况下在 MySQL 中获得更高的计算距离精度?

标签 mysql precision distance latitude-longitude

我必须计算一个对象(一个城市)与我拥有的 MySQL 表(一些餐馆)中的每个条目之间的距离。这个城市和餐馆位于同一个国家。

计算的距离用于显示靠近该城市的所有餐馆;阈值距离是任意的。 此外,这是一个排名列表:最先显示最近的餐厅,最远的餐厅显示在列表末尾。我的问题是关于这个排名。

我现在做了什么

所以我做了一些研究,我成功地计算出了这个距离。

    $special_select_distance = "DEGREES(ACOS(COS(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * COS(RADIANS(lat)) * COS(RADIANS(lon) - RADIANS(" . $oneVilles->__get('longitude')[app::getLang()] . ")) + SIN(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * SIN(RADIANS(lat))))";

    $restaurants = $restaurantsDAO->getAll(null, ['distance DESC'] , null, 'HAVING distance < 1.9' , null , '*, ' . $special_select_distance . " AS distance");

...其中:

  1. ['distance DESC']代表距离排名

  2. 'HAVING distance < 1.9'代表任意阈值

  3. '*, ' . $special_select_distance . " AS distance"是选择器

  4. $oneVilles->__get('latitude')[app::getLang()]$oneVilles->__get('longitude')[app::getLang()]是城市的经纬度坐标

  5. latlon是餐厅的坐标(自动进入我们迭代的表,即: restaurants 表,因为我们使用餐厅 DAO)

问题

实际和意外结果

对于彼此距离很近的每家餐馆,计算出的与城市的距离保持不变。

示例:假设餐厅 A 和 B 距离很近。那么,A到城市的距离等于B到城市的距离,这是我实际的意外结果。

这不是我想要的。事实上,这些餐厅中有一家比另一家离市区最近。我认为 MySQL 不够精确。

预期结果

预期结果:让餐厅按照到工作城市的远近排名。换句话说,获得更精确的计算距离。

示例:假设餐厅 A 和 B 距离很近。那么,A到城市的距离比B到城市的距离短,这是我的预期结果。

计算距离的例子

  1. 在餐厅和城市之间(餐厅远离城市):1.933156948976873

  2. 在餐厅 A 和城市之间(A 靠近城市):1.6054631070094885

  3. 在餐厅 B 和城市之间(B 靠近 A):1.6054631070094885

点 2. 和点 3. 的距离相同,这不正常。我想要更多数字,以便能够更有效地对我的餐厅进行排名。

约束

  • 我不想更改 MySQL 服务器的配置。

    • 特别是:我绝对不能使用 MySQL 几何类型(这是公司的限制)
  • 预期的解决方案应该只是更改我编写并提供给您的 SQL 查询,以便在可能的情况下更加精确。

  • 如有必要,允许使用其他计算距离的方法。

最佳答案

对于长距离,请使用 Haversine 公式来确保准确性。对于短距离,毕达哥拉斯的速度是其两倍。

16 位有效数字(数据类型 DOUBLE)很可笑。您无需区分狗身上的两种不同跳蚤。

对于毕达哥拉斯,一定要将经度除以纬度的余弦——赫尔辛基附近的经度一度是赤道一度的一半。

更多细节在这里:http://mysql.rjweb.org/doc.php/latlng

如果 1.6054631070094885 是纬度差异,那么可以这样想:如果你我在同一经度,但我们的纬度分别是 1.605463 和 1.605464,那么,好吧,我不非常了解您,可以接近您。

在没有软糖因素的情况下比较两个浮点值是不切实际的:

If abs(a-b) < 0.00001, then treat them as equal.

更多

我推荐 FLOAT 用于纬度、经度和距离,因为您在谈论餐馆。如果您谈论的不是超过 100 英里或 100 公里,那么这个表达式就足够精确了:

SQRT(  ($lat - lat) *
       ($lat - lat) +
      (($lng - lng) * COS(RADIANS(lat))) *
      (($lng - lng) * COS(RADIANS(lat))) )  * $factor

哪里...

  • latlng 是表中 FLOAT 列的名称,以度为单位。
  • $lat$lng 是您起始位置的值,也以度为单位。 (PHP 使用 $;其他语言使用其他约定。)
  • $factor 是 69.172 英里或 111.325 公里。
  • 我不会显示超过 1 位小数的结果。 (不要显示“12.345678 英里”;“12.3 英里”就足够了。)

毕达哥拉斯和 GCD 的比较:

             Pyt        GCD
To Rennes:  93.9407    93.6542
To Vannes:  95.6244    95.6241

关于mysql - 如何在不使用几何类型的情况下在 MySQL 中获得更高的计算距离精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54237933/

相关文章:

.net - 有没有办法得到小数的 "significant figures"?

python - 从 numpy 距离数组中提取 N 个最近的对

php - 将 3 个查询组合成一个数组

where `case when` 中的 MySQL 子句

c# - 为什么在 C# 中将 double 转换为 float 时我的精度会下降?

math - float 学有问题吗?

android - distanceTo 返回的距离是多少?

sql-server-2008 - 查询将特定地理距离内的行返回给定行(使用sql server 2008)

java - MySQL: org.hibernate.HibernateException: 找到超过一行的给定标识符 3

mysql - 如何在 MySQL 中查找非 ASCII 字符?