繁体   English   中英

MySQL选择范围内的坐标

[英]MySQL select coordinates within range

我的数据库中有 100 000 个地址(即记录)。

他们每个人都有自己的坐标(纬度和经度)。

现在,给定用户的地理位置(纬度和经度),我想在地图上仅显示 5 英里范围内的地址(使用 Google maps v3 API)。

这意味着通常只需要显示 100 000 个地址中的 5 或 6 个地址。

一种解决方案可能是检索所有记录并在 Java 中应用一个公式来计算每个地址的距离,并且仅当它在范围内时才显示它。

这将浪费处理能力,因为我需要检索所有记录,而我只需要在地图上显示 5 或 6 条记录。

如何在数据库端(MySQL)解决这个问题,以便只返回 5 英里范围内的地址?

您可以使用所谓的Haversine 公式

$sql = "SELECT *, ( 3959 * acos( cos( radians(" . $lat . ") ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(" . $lng . ") ) + sin( radians(" . $lat . ") ) * sin( radians( lat ) ) ) ) AS distance FROM your_table HAVING distance < 5";

其中$lat$lng是您点的坐标,而 lat/lng 是您的表格列。 以上将列出 5 nm 范围内的位置。 3959替换为6371以更改为公里。

此链接可能有用: https : //developers.google.com/maps/articles/phpsqlsearch_v3

编辑:我没有看到你提到 Java。 这个例子是用 PHP 编写的,但查询仍然是你需要的。

我认为 MySQL 的地理空间扩展可以为您解决这个问题: https : //dev.mysql.com/doc/refman/8.0/en/spatial-convenience-functions.html#function_st-distance-sphere

否则,您可以在纬度上建立索引,然后查询 WHERE lattitude > userLat-5miles 和 lattitude < userLat+5miles。 这将大大减少应用层中可能处理的行数。

我的方法 - 我正在使用它 - 像技术人员一样思考,我对 +/- 5% 感到满意

这个解决方案不是为了控制火箭、船只或类似的东西,只有在~100公里以下的距离,它只是一个像费米问题一样的解决方案

所以让我们开始一个务实的解决方案:

第一:对于很多问题我们可以忽略地球不平坦(距离<~100km),

地球的周长或多或少是 40000 公里(或多或少由于某种原因)

一个圆正好有 360 度。

所以 1 公里是:360/40000 度 => 0.00278 度

然后只需在每公里 0.003 范围内选择纬度/经度,这将类似于 long > 42 - 0.003 和 long < 42 + 0.003 - 纬度相同,其中 42 是您的纬度/经度作为中点。 数据库将使用索引。

问题:你得到一个正方形而不是一个圆(不是真正的距离)

如果您需要圆圈,请在获得结果后编写脚本。

我只是在 2 公里内显示官方厕所,所以一个正方形是可以的,而且准确性也是如此。 原因是,有街道和房子,所以人们不能直接走路......

编辑:技术/数学解释:

对于非常小的三角形(一个角度<< 5 度),您可以忽略三角函数的使用。 所以罪(5度)~= 5/180*PI

DELIMITER $
DROP FUNCTION IF EXISTS calc_distance$

CREATE FUNCTION calc_distance(
    user_lat FLOAT(9,6),
    user_lng FLOAT(9,6),
    field_lat FLOAT(9,6),
    field_lng FLOAT(9,6)
) RETURNS INTEGER

BEGIN
    DECLARE ulat FLOAT;
    DECLARE ulng FLOAT;
    DECLARE flat FLOAT;
    DECLARE flng FLOAT;

    SET ulat = RADIANS(user_lat);
    SET ulng = RADIANS(user_lng);
    SET flat = RADIANS(field_lat);
    SET flng = RADIANS(field_lng);
    RETURN
        6371393
        * ACOS(
            COS(ulat) * COS(flat) * COS(flng - ulng)
            + SIN(ulat) * SIN(flat)
        );
END$
DELIMITER ;

用法

if (($radius = $search->getRadiusMeters())) {
    $query['where'][] = "calc_distance($lat, $lng, addr.lat, addr.lng) < $radius";
}

我的数据库中有10万个地址(即记录)。

它们每个都有自己的坐标(纬度和经度)。

现在,鉴于用户的地理位置(经度和纬度),我想在地图上仅显示5英里范围内的地址(使用Google Maps v3 API)。

这意味着通常必须在100 000个地址中仅显示5个或6个地址。

一种解决方案是检索所有记录,并在Java中应用公式来计算每个地址的距离,并仅在其位于范围内时显示它。

那将浪费处理能力,因为当我只需要在地图上显示5或6条记录时,我就需要检索所有记录。

我如何在数据库端(MySQL)上解决此问题,以便仅返回5英里范围内的地址?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM