在 MySQL 中查找与纬度经度最近的邮政编码

Posted

技术标签:

【中文标题】在 MySQL 中查找与纬度经度最近的邮政编码【英文标题】:Find nearest postcode to Latitude Longitude in MySQL 【发布时间】:2012-10-17 12:52:00 【问题描述】:

我有一张 Postcode 表格,其中包含所有英国邮政编码(我认为大约 180 万)

CREATE TABLE `Postcode` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Postcode` varchar(8) DEFAULT NULL,
  `Postcode_Simple` varchar(8) DEFAULT NULL,
  `Positional_Quality_Indicator` int(11) DEFAULT NULL,
  `Eastings` int(11) DEFAULT NULL,
  `Northings` int(11) DEFAULT NULL,
  `Latitude` double DEFAULT NULL,
  `Longitude` double DEFAULT NULL,
  `LatLong` point DEFAULT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `Postcode` (`Postcode`),
  KEY `Postcode_Simple` (`Postcode_Simple`),
  KEY `LatLong` (`LatLong`(25))
) ENGINE=InnoDB AUTO_INCREMENT=1755933 DEFAULT CHARSET=latin1;

我想要实现的是...给定一个坐标,找到离坐标最近的邮政编码。问题是我为执行此操作而编写的查询(实际上是在存储过程中)遇到了一些问题。查询是:

SELECT
    Postcode
FROM
    (SELECT
        Postcode,
        GLENGTH(
            LINESTRINGFROMWKB(
                LINESTRING(
                    LatLong, 
                    GEOMFROMTEXT(CONCAT('POINT(', varLatitude, ' ', varLongitude, ')'))
                )
            )
        ) AS distance
    FROM
        Postcode
    WHERE
        NOT LatLong IS NULL) P
ORDER BY
    Distance
LIMIT
    1;

我遇到的问题是查询需要大约 12 秒才能运行,而且我不能花那么长时间才能得到结果。谁能想到我可以可靠地加快这个查询的任何方法?

(这里是查询的解释)

id select_type table      type possible_keys key    key_len ref    rows    Extra
1  PRIMARY     <derived2> ALL  (NULL)        (NULL) (NULL)  (NULL) 1688034 Using filesort
2  DERIVED     Postcode   ALL  LatLong       (NULL) (NULL)  (NULL) 1717998 Using where

我一直在想办法缩小我必须执行距离计算的初始数据量,但我无法想出任何不限于查找邮政编码的方法在给定的距离内。

【问题讨论】:

你创建了索引,PKs,表结构是什么?加快查询速度 @jcho360 索引和主键已经创建,但不利于为我正在使用的查询创建交易。表结构已经如上图... 【参考方案1】:

也许可以尝试以下方式:

SELECT Postcode, lat, lon
FROM
(
SELECT Postcode, MAX(latitude) AS lat, MAX(longitude) AS lon
FROM PostCode

-- field name
GROUP BY Postcode 

HAVING MAX(latitude)<varLatitude AND MAX(longitude)<varLongitude

LIMIT 1
) AS temp

这基本上会带来纬度和经度小于您指定但大于任何其他纬度/经度组合且小于您的变量的邮政编码;如此有效地与您的变量最近的纬度/经度,因此最接近的邮政编码。您可以使用 MIN 和更大的 then 尝试相同的方法,而不是反过来。

以上内容只会为您提供一个结果/邮政编码。如果你想找到一些更漂亮的东西,比如找到一组以特定纬度/经度半径给出的邮政编码,那么你应该看看https://developers.google.com/maps/articles/phpsqlsearch_v3#findnearsql 中解释的公式

【讨论】:

这似乎让我得到了正确的坐标,但是子查询中返回的邮政编码不是与返回的坐标匹配的邮政编码。这将取决于聚合函数,因此我必须使用返回的坐标来获取邮政编码,这意味着它们也需要被索引。不过,我将进一步研究此解决方案,因为它确实可以非常快速地缩小数据范围。 @JohnHenry 对不起我的错误,应该使用 HAVING 而不是 WHERE,根据需要在答案中进行更新 两者的区别在于虽然相似,但是HAVING会根据聚合函数返回记录,而WHERE不会考虑到它们。此外,如果您添加 GROUP BY 邮政编码和 LIMIT,您应该能够获得最近的邮政编码列表 嗯,我似乎根本无法使用此方法,它似乎返回了很多不需要的和不准确的结果。 唉,这似乎也不起作用。我会看看我还能想出什么。非常感谢您的所有帮助,非常感谢!!!【参考方案2】:

我已经写了一个tutorial 几乎正是你所追求的。

基本上,您是在正确的路线上。为了提高搜索效率,您需要通过在 LatLong 字段上使用空间索引来减少 GLength() 计算的数量。如果您将搜索限制在一个细化的区域,例如与邮政编码比较的点周围 10 英里的多边形,您会发现查询要快得多。

【讨论】:

以上是关于在 MySQL 中查找与纬度经度最近的邮政编码的主要内容,如果未能解决你的问题,请参考以下文章

从邮政编码表(MySql)获取纬度和经度并加入另一个表

如何在 PHP 中对谷歌地理编码 api 进行批量纬度/经度查找?

在 SQL Server 中查找多边形内/最近的纬度/经度

查找提供的纬度和经度的最近距离记录的程序[重复]

在mysql中使用纬度和经度查找两点之间的距离

地理编码器谷歌地图经度和纬度查找