使用空间点类型在 MySQL 中存储 Lat Lng 值

Posted

技术标签:

【中文标题】使用空间点类型在 MySQL 中存储 Lat Lng 值【英文标题】:Storing Lat Lng values in MySQL using Spatial Point Type 【发布时间】:2011-06-27 02:18:11 【问题描述】:

使用的技术:mysql 5.1 和 php 5.3

我只是为我正在编写的网站设计一个新数据库。我正在寻找现在存储 Lat 和 Lng 值的最佳方式。

过去我一直使用 DECIMAL 并在表单中使用 PHP/MySQL 选择:

SQRT(POW(69.1 * (fld_lat - ( $lat )), 2) + POW(69.1 * (($lon) - fld_lon) * COS(fld_lat / 57.3 ), 2 )) AS distance

寻找最近的匹配地点。

开始阅读有关新技术的更多信息,我想知道是否应该使用 Spatial Extensions。 http://dev.mysql.com/doc/refman/5.1/en/geometry-property-functions.html

不过,实际信息非常少,并且对如何存储数据存在疑问。我现在不使用 DECIMAL,而是使用 POINT 作为数据类型吗?

此外,一旦存储为 POINT,是否可以轻松地从中获取 Lat Lng 值,以防我想在地图上绘制它,或者我是否应该另外将 lat lngs 再次存储为 DECIMALS?

我知道我应该使用 PostGIS,因为这里的大多数帖子都说我只是不想学习新的数据库!

跟进

我一直在玩新的 POINT 类型。我已经能够使用以下方法添加 Lat Lng 值:

INSERT INTO spatialTable (placeName, geoPoint) VALUES( "London School of Economics", GeomFromText( 'POINT(51.514 -0.1167)' ));

然后我可以使用以下方法从 Db 中获取 Lat 和 Lng 值:

SELECT X(geoPoint), Y(geoPoint) FROM spatialTable;

这一切看起来都不错,但是距离的计算是我需要解决的问题。显然 MySQL 有一个用于距离函数的占位符,但暂时不会发布。在一些帖子中,我发现我需要执行以下操作,但是我认为我的代码有点错误:

SELECT
 placeName,
 ROUND(GLength(
  LineStringFromWKB(
   LineString(
    geoPoint, 
    GeomFromText('POINT(52.5177, -0.0968)')
  )
  )
))
AS distance
FROM spatialTable
ORDER BY distance ASC;

在本例中,geoPoint 是使用上述 INSERT 输入数据库的 POINT。

GeomFromText('POINT(52.5177, -0.0968)' 是我要计算距离的 Lat Lng 值。

更多跟进

相当愚蠢,我只是在没有真正考虑的情况下放入了 SQL 的 ROUND 部分。把它拿出来给我:

SELECT
placeName,
(GLength(
LineStringFromWKB(
  LineString(
    geoPoint, 
    GeomFromText('POINT(51.5177 -0.0968)')
  )
 )
))
AS distance
FROM spatialTable
ORDER BY distance ASC

这似乎给了我所需的正确距离。

我想目前唯一需要回答的问题是,我是否只是通过现在使用 Spatial 让自己过上困难,还是让自己适应未来……

【问题讨论】:

未来证明:You Aren't Gonna Need It 非常有用的信息。 不,你确实需要它。如果您想使用 MySQL 并(快速)搜索某个点附近的地方,则需要空间索引。 距离是用哪个单位计算的? 是的,距离是用什么单位计算的? 【参考方案1】:

我认为您应该始终使用易于获得的***别抽象。如果您的数据是地理空间数据,则使用地理空间对象。

但要小心。 Mysql 是最糟糕的地理空间数据库。它可以用于点,但它的所有多边形功能都完全被破坏了 - 他们将多边形更改为其边界矩形,然后对此进行回答。

让我印象最深的例子是,如果你有一个代表日本的多边形并且你问日本有哪些地方,符拉迪沃斯托克就会进入列表!

Oracle 和 PostGIS 没有这个问题。我希望 MSSQL 不会,任何使用 JTS 作为其引擎的 Java 数据库都不会。地理空间好。 MySQL 地理空间错误。

请阅读此处How do you use MySQL spatial queries to find all records in X radius?,它已在 5.6.1 中修复。

万岁!

【讨论】:

事情已经改变。当一个我们的 MBR 函数依赖于计算 minimum bounding rectangle 时,会发生 mysql 错误的多查询。从 mysql 5.6 开始。新功能出现了。以“st_*”开头的函数执行得更好。例如contains(g1, g2)st_contains(g1, g2)。更多信息请访问percona.com/blog/2013/10/21/… 是的,我认为 OpenGIS 决定 st_ 名称在数据库供应商之间更具可移植性。绝对应该使用它们。不过,我认为它们在 5.6 中并不准确。 请注意,在 `5.6.23-72.1 - Percona Server (GPL)` 上, st_contains 似乎按预期工作。仅针对附近(即:最多 800 公里距离)坐标进行测试。也许对于长距离坐标它的表现不同 搜索更深入***.com/questions/7782873/… 说 5.6.1 符合您的经验。【参考方案2】:

Mysql GIS 雅格尼:

如果您没有使用 GIS 的经验,那么学习空间扩展实际上就像学习一个新数据库,再加上一点数学知识和许多首字母缩略词。地图,投影,srids,格式......你是否必须学习所有这些来计算给定纬度/经度的点之间的距离:可能不是,你会整合第 3 方 GIS 数据还是使用比点更复杂的东西,什么您将使用坐标系吗?

回到 yagni:做尽可能简单的事情,在这种情况下,用 php 或使用简单的 SQL 实现您的代码。一旦您遇到障碍并决定您需要空间,请阅读 GIS 系统、坐标系、项目和约定。

到那时,您可能会想要 PostGIS。

【讨论】:

【参考方案3】:

这是一件好事,因为这样您就可以在查询中使用空间索引。限制为边界框,例如,限制要比较的行数。

【讨论】:

【参考方案4】:

如果您可以在后端添加一些额外的代码,请使用 Geohash。

它以前缀表示更广泛区域的方式将坐标编码为字符串。字符串越长,精度越高。

它具有多种语言的绑定。

http://en.wikipedia.org/wiki/Geohash https://www.elastic.co/guide/en/elasticsearch/guide/current/geohashes.html

【讨论】:

以上是关于使用空间点类型在 MySQL 中存储 Lat Lng 值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用具有球形几何形状的 MySQL 地理空间扩展

如何在普通mysql中进行地理空间搜索

使用 R 将 lat/long 点的数据框空间连接到多边形 shapefil

Mysql空间索引

在 Loopback 4 中处理 GeoLocation 并存储为 MySQL 点

Oracle二维表管理:约束