在mySQL中测量半径内位置的正确方法是啥?

Posted

技术标签:

【中文标题】在mySQL中测量半径内位置的正确方法是啥?【英文标题】:What's the right way to measure locations within a radius in mySQL?在mySQL中测量半径内位置的正确方法是什么? 【发布时间】:2014-10-24 03:51:15 【问题描述】:

我正在编写一个应用程序,该应用程序需要允许用户选择其位置半径范围内的元素。没有办法知道最终会有多少个位置,但它可能是数万个。进行搜索的用户是位置节点之一(而不仅仅是他们的手机或其他提交的任意位置)

我看到这样的答案:mysql lat lon calulation to show locations within radius 但我担心这是一项非常严肃的工作,因为需要为每个“其他”位置计算所涉及的数学。

我正在考虑的另一种方法是有一个关系表来标识每个位置之间的距离(每次添加位置时我都会填充),授予它将有大量行来定义每个可能的关系,但是随后选择 *该表将非常快,尤其是在对距离进行索引的情况下。

很想从在 mySQL 中做过这件事的人那里得到一些建议,并且可以警告/建议我支持或反对最佳方法。

【问题讨论】:

【参考方案1】:

以下 SQL 查询使用Spherical Law of Cosines 计算坐标与表中坐标之间的距离。它将结果限制为 10 并按距离排序。这用于代替过于复杂而无法使用 MySQL 执行的 Haversine 公式

余弦球定律

其中 R = 3,959 英里或 6,371 公里

d = acos( sin(lat1).sin(lat2) + cos(lat1).cos(lat2).cos(lng2-lng1) ).R

SQL

SELECT  name, lat, lng, ( 3959 * acos( cos( radians($center_lat) ) 
                        * cos( radians( lat ) ) * cos( radians( lng )
                        - radians($center_lng) ) + sin( radians($center_lat) ) 
                        * sin( radians( lat ) ) ) ) AS distance FROM table 
                        ORDER BY distance LIMIT 0 , 10

其中$center_lat$center_lng 是位置坐标。

查询使用SQL Math functions

在有 50,068 行的数据库上查询耗时 0.2506 秒

MySQL 中可用的空间函数不适合您的 porpose,请参阅Blog

【讨论】:

当您说 R=3959 时,您的意思是它找到了距 center_lng,center_lat 距离内的每个位置,然后将结果限制为 10?如果我将该半径减小到 50 但不设置限制并让它给我落入该圆圈的每个结果,它会显着变慢吗? 移除 LIMIT 应该不会影响执行查询的时间,但会影响显示结果的时间。【参考方案2】:

GIS 是开始计算半径距离的好地方,但最终(规模)您将不得不分解为经纬度网格。半径计算成本很高,网格在哪里存储和查找非常简单。根据我的经验,MySQL 中的 FWIW GIS 功能在 5.6 之前的许多内核(10+)上不能很好地扩展,并且可能要到 5.7 才能修复。

【讨论】:

【参考方案3】:

如果您预先计算了一些您实际需要的数据并将其存储在数据库中,那么根据该数据进行一些计算应该会非常快。

根据我对这个问题的回答:

Sorting zip code proximity question on SO

你可以使用类似的计算

$iRadius * 2 * ASIN(SQRT(POWER(SIN(( $fLat - abs(pos.lat)) * pi() / 180 / 2),2) +
COS( $fLat * pi()/180) * COS(abs(pos.lat) * pi() / 180) * POWER(SIN(( $fLon - pos.lon) *
pi() / 180 / 2), 2) )) AS distance

实际数学函数的负载可以预先计算并存储在数据库中。这应该可以帮助您加快查询速度。

如果您知道您只对特定半径感兴趣,您甚至可以忽略差异较大的纬度/经度值(因为这已经暗示它们具有特定距离),因此您只需计算纬度/经度您所在位置的特定范围内的值。

我使用这种方法在 0.1 秒内计算到邮政编码 (>60.000) 的距离

问题始终是:您需要计算多少个值?

【讨论】:

以上是关于在mySQL中测量半径内位置的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

python:使用纬度和经度查找提供位置半径内的位置的优雅方法

获取半径内的位置

获取半径内的位置

MATLAB数学实验问题

RationalDMiS 2020测头补偿

在 C++ 预印卡上打印的最简单方法是啥?