【问题标题】:Effectively selecting the closest (distance) record from a database有效地从数据库中选择最近(距离)的记录
【发布时间】:2020-07-14 08:29:12
【问题描述】:

我有一个包含 40k 场馆的数据库,并且现在还在增长。

假设我是红点


我希望能够尽快检索到最近的记录。

但是下一个项目的距离也可以是任何东西。并且也可能有 0-n 匹配。但是当我只是在寻找 1 时,我是否需要加载所有 40000 个结果?

如何按距离对记录进行排序?应该在 MYSQL 还是 PHP 中完成? 这种计算几乎发生在每个请求、每个用户、每个页面上,因此解决方案需要快速。

编辑感谢您提供快速而有希望的答案,我需要查看这些资源,并会在几天内接受/评论答案。

【问题讨论】:

  • 您是否尝试过在查询中包含到场地的距离(通过使用计算列)并查看它的速度有多慢?
  • @Sam Holder 我使用简单的毕达哥拉斯计算运行查询,以检查交叉口附近有哪些场地,脚本执行比分配给交叉口的场地慢 1-2 秒。 (对于一台电脑来说,我觉得是很久了)
  • 好的,很好。我只是在检查是否先完成了显而易见的事情,并且简单的解决方案不合适:)

标签: mysql math distance


【解决方案1】:

这个 Scribd 演示文稿(理论 + 数学公式 + Mysql)涵盖了这个问题: Geo Distance with MySQL

我希望它涵盖了你需要的一切

【讨论】:

    【解决方案2】:

    最简单的解决方案是简单计算每条记录的距离并按此值排序。问题是:这非常昂贵并且您不能为此使用索引。您可以通过仅查看记录的子集来降低成本,也许像这里的一些海报所建议的那样受到边界框的限制。

    如果您想要一个清晰快速的解决方案,请查看 MySQL 的 Spatial Extensions。这些正是为您想做的事情而制作的。这些支持:

    • 一种新的列型“点”
    • 一种针对距离查询优化的特殊索引类型
    • 距离操作员。

    Thishowto 提供了一些示例:

    CREATE TABLE address (
      address CHAR(80) NOT NULL,
      address_loc POINT NOT NULL,
      PRIMARY KEY(address),
      SPATIAL KEY(address_loc)
    );
    CREATE TABLE cab (
      cab_id INT AUTO_INCREMENT NOT NULL,
      cab_driver CHAR(80) NOT NULL,
      cab_loc POINT NOT NULL,
      PRIMARY KEY(cab_id),
      SPATIAL KEY(cab_loc)
    );
    
    SELECT
      c.cab_driver,
      ROUND(GLength(LineStringFromWKB(LineString(AsBinary(c.cab_loc),
                                                 AsBinary(a.address_loc)))))
        AS distance
    FROM cab c, address a
    WHERE a.address = 'Foobar street 110'
    ORDER BY distance ASC LIMIT 1;
    

    【讨论】:

    • 请注意,与通常的数据库索引相比,有一个特殊的空间索引可以利用
    【解决方案3】:

    按照article on Movable Type(带有 PHP 代码示例)中所述,创建一个“边界框”以在 SQL 查询中的 WHERE 子句中使用,然后在查询中包含 Haversine 公式以计算实际距离,并订购结果由距离 ASC。然后,最近的地点将是结果集中的第一个返回。

    边界框有助于提高性能,因为这意味着您只需要对一小部分数据进行昂贵的距离计算

    如果初始查询没有返回任何记录,请扩大边界框,然后再次执行查询,直到得到响应。

    【讨论】:

      【解决方案4】:

      除了反复试验,没有有效的方法可以找到距离。也就是说,使用 MySQL,您不能按与目标的距离对记录进行排名,然后选择顶部的记录。最好的方法是选择一个您认为最接近记录的距离。数字太大,您将获得太多记录,数字太小,您将一无所获。假设您选择了 40 个单位。

      WHERE xcoord BETWEEN n - 40 AND n + 40 AND ycoord BETWEEN n - 40 AND n + 40
      

      现在您已经在一个 80 x 80 的框内获得了所有坐标的记录,以您的目标为中心(如果您在纬度和经度中工作,该框会有点倾斜,但事实并非如此' t真的很重要)。现在,如果您使用纬度和经度,则使用 Haversine 方程,如果只是笛卡尔坐标,则使用毕达哥拉斯方程来计算目标与每个点之间的距离。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-11
        • 2012-07-08
        • 1970-01-01
        相关资源
        最近更新 更多