【问题标题】:MySQL - Find points within radius from databaseMySQL - 从数据库中查找半径内的点
【发布时间】:2017-08-05 13:31:50
【问题描述】:

我有一个表格,其中有一个 POINT 列,其中包含各个位置的纬度和经度。

然后我在浏览器中也有一个来自地理位置的用户位置。

我需要做的是从表中查找所有记录,其中POINT 值在 10 公里半径(或 X 公里半径)内,按距离排序,距离最近的在前。

我的表在POINT 列上有一个SPATIAL 索引。

【问题讨论】:

  • 您无法使用索引在圆内找到点 - 但如果您为索引查找定义边界框,然后根据与中心的距离进行过滤,您将获得快速的结果。跨度>
  • 这里给出的解决方案不适用于大型数据集。如果这是一个问题,请参阅mysql.rjweb.org/doc.php/find_nearest_in_mysql

标签: mysql geospatial spatial


【解决方案1】:

下面的查询实际上对我有用:

$query = "SELECT *,
    ( 6371 * 
    acos( 
    cos( radians( ".$user_lat." ) ) * 
      cos( radians( lat ) ) * 
      cos( radians( lng ) - 
      radians( ".$user_lng." ) ) + 
        sin( radians( ".$user_lat." ) ) * 
          sin( radians( lat ) ) ) ) 
          AS distance FROM parkings 
          HAVING distance <= ".$radius." ORDER BY distance ASC";

  $stmt = $conn->execute($query);

  $rows = $stmt->fetchAll('assoc');

在哪里: $user_lat 和 $user_lng 是浏览器的 lat 和 lng, $半径 = 10, 表名是parkings

【讨论】:

    【解决方案2】:

    我目前正在进行一个项目,我正在计算多个位置之间的距离。我正在使用以下查询来选择给定半径内的 object_id。

    SELECT id, 
    ( 6371 * 
        ACOS( 
            COS( RADIANS( db_latitude ) ) * 
            COS( RADIANS( $user_latitude ) ) * 
            COS( RADIANS( $user_longitude ) - 
            RADIANS( db_longitude ) ) + 
            SIN( RADIANS( db_latitude ) ) * 
            SIN( RADIANS( $user_latitude) ) 
        ) 
    ) 
    AS distance FROM the_table HAVING distance <= $the_radius ORDER BY distance ASC"
    

    我无法解释 ACOS 公式本身,因为我是从研究中得到的。

    db_latitude = database latitude field
    db_longitude = database longitude field
    $user_latitude = browser latitude coördinate
    $user_longitude = browser longitude coördinate
    $the_radius = the radius that you want to search in
    

    以公里为单位。

    【讨论】:

    • 嗨@Bas,谢谢你,但我的纬度/经度存储为 MySQL POINT 字段而不是两个单独的浮点数。我的理解是这是存储此信息的正确方法,因此我可以拥有一个SPATIAL 索引以提高效率。
    • 嗨@tip2tail,很抱歉我忽略了这个细节。我不熟悉“POINT”字段。找到这个堆栈帖子希望它可以帮助你stackoverflow.com/a/21170928/5567106
    • 这就是答案,尽管我必须通过 MySQL 的 X() 和 Y() 函数将我的 POINT 输出到经纬度。
    • 如果您需要以 MILES 为单位的范围,请将“6371”替换为“3959”。
    • @Bas van Dijk ,您正在为每一行选择纬度和经度,然后计算到用户输入点的“距离”(更不用说,您正在使用昂贵的三角函数)。然后按半径过滤结果。是的,每次运行查询时都会遍历表中的每一行。使用 EXPLAIN 查看使用了多少行。但是对于 17k 行,并且一次只有几个查询,这将起作用。不是当您拥有大量行和更多访问权限时,它根本无法扩展。我不会在生产中使用它。
    【解决方案3】:

    也许这对你有帮助, https://ru.scribd.com/presentation/2569355/Geo-Distance-Search-with-MySQL

    对于 Django,我使用这个

        dist = 20 #дистанция 20 км
        mylon = 51.5289156201 # долгота центра
        mylat = 46.0209384922 # широта 
        lon1 = mylon-dist/abs(math.cos(math.radians(mylat))*111.0) # 1 градус широты = 111 км
        lon2 = mylon+dist/abs(math.cos(math.radians(mylat))*111.0)
        lat1 = mylat-(dist/111.0)
        lat2 = mylat+(dist/111.0)
        profiles = UserProfile.objects.filter(lat__range=(lat1, lat2)).filter(lon__range=(lon1, lon2))
    

    它会搜索 20 公里内的所有用户。

    【讨论】:

    • 嗨@Nickita,谢谢。这看起来与上面的答案非常相似,请在那里查看我的 cmets。
    猜你喜欢
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多