带有位置数据的大型 MySQL 数据库(21MM 记录) - 每个位置都有经纬度 - 需要运行“附近”查询

Posted

技术标签:

【中文标题】带有位置数据的大型 MySQL 数据库(21MM 记录) - 每个位置都有经纬度 - 需要运行“附近”查询【英文标题】:Large MySQL DB (21MM records) with location data - each location has lat and long - need to run 'nearby' query 【发布时间】:2011-07-29 02:33:26 【问题描述】:

我们有一个大型位置数据库 - 为每一行指定了 lat long。数据库托管在 mysql 中。

我们需要运行两种类型的查询:

附近的地点(按距离排序) 按类别划分附近的地点(其中类别是一列)

随着记录数量的增加,这个查询似乎急剧变慢了。

SELECT *, ( 3959 * acos( cos( radians(40.759105) ) * cos( radians( Latitude ) ) * cos( radians( longitude) - radians(-73.984654) ) + sin( radians(40.759105) ) * sin( radians( Latitude ) ) ) ) as distance FROM mcw_in WHERE Latitude <> '' ORDER BY distance LIMIT 0,20

如何在 MySQL 中创建索引来解决缓慢的问题?有没有其他解决方案——比如使用任何地理空间数据类型?

【问题讨论】:

【参考方案1】:

MySQL Manual :: Introduction to MySQL Spatial Support

MySQL Manual :: Creating Spatial Indexes

【讨论】:

【参考方案2】:

但实际上这在 MySQL 中是行不通的,因为它们还没有真正实现这些功能。

如果您愿意,我会推荐使用 PostGIS 或 Spatialiate(分别在 Postgresql 和 SQLLite 上运行)甚至 mongodb 或 geocouch。它们具有更大的一套已实现的空间功能。如果您查看 MySQL 文档,它大多说空间函数“未实现”。

【讨论】:

【参考方案3】:

最好通过定义围绕中心的边界框来使用范围查询。以下查询搜索距中心 ($lat0, $lng0) 距离 $dist 内最近的 20 个位置,结果按距离排序。您需要两个索引,一个在“lat”上,一个在“lng”上。一些解释可以在here找到。

SELECT *,
    ( 6371 * acos(
    cos(radians($lat0)) * cos(radians(lat)) * cos(radians(lng) - radians($lng0)) +
    sin(radians($lat0)) * sin(radians(lat))
    ) ) AS distance
FROM `locations`
WHERE lat < degrees( asin( sin(radians($lat0)) * cos($dist / 6371) +
        cos(radians($lat0)) * sin($dist / 6371) * cos(radians(0)) ))
  AND lat > degrees( asin( sin(radians($lat0)) * cos($dist / 6371) +
        cos(radians($lat0)) * sin($dist / 6371) * cos(radians(180)) ))
  AND lng < $lng0 - degrees( atan2(sin(radians(90)) * sin(radians($dist / 6371)) * cos(radians($lat0)),
        cos(radians($dist / 6371)) - sin(radians($lat0)) * sin(radians($lat0))) )
  AND lng > $lng0 + degrees( atan2(sin(radians(90)) * sin(radians($dist / 6371)) * cos(radians($lat0)),
        cos(radians($dist / 6371)) - sin(radians($lat0)) * sin(radians($lat0))) )
ORDER BY distance LIMIT 20;

【讨论】:

以上是关于带有位置数据的大型 MySQL 数据库(21MM 记录) - 每个位置都有经纬度 - 需要运行“附近”查询的主要内容,如果未能解决你的问题,请参考以下文章

mysql 查询一年的数据 要按每个月20号统计 如何做 一条语句

导入大型数据库 - CPanel & MySQL & PHPMyAdmin

如何将大型 MySQL 数据库从一台服务器迁移到另一台服务器?

将时间 dd/mm/yyyy 转换为 R 中的数字

需要通过 PHP 将大型 CSV 文件导入多个 MySQL 表的高效方法

centos7上安装mysql5.7.21流程