【问题标题】:How do I query a table with a geospatial "point" field in MySQL如何在 MySQL 中使用地理空间“点”字段查询表
【发布时间】:2014-04-09 22:40:47
【问题描述】:

我有一个“地点”表,其中包含 lat、lng 和 point 字段。我一直在使用半正弦公式来计算 lat,lng 方面的距离,但我读到使用点场更有效?我只是找不到任何有关如何执行此操作的文档。这是我的查询,因为它现在查询所有地方并按距离排序

 SELECT `places`.*, `places`.`id` AS `pid`,   
        ((6371*acos(cos(radians(37.776708))*cos(radians(lat))*
          cos(radians(lng)-radians(-122.398050))+sin(radians(37.776708))*
          sin(radians(lat))))*1000) AS `distance` 
   FROM `places` 
  WHERE `page_id` IS NOT null 
  ORDER BY `distance` ASC 
  LIMIT 40 OFFSET 0

如何更改它以使用表格中的“点”字段而不是 lat/lng

【问题讨论】:

    标签: mysql sql geolocation geospatial


    【解决方案1】:

    您需要做一些事情才能将 MySQL 地理空间扩展用于此类事情。

    1. 您必须为您的地理空间数据使用 MyISAM 表。
    2. 您的表中需要有一个GEOMETRY 列,并且它不能为空。
    3. 您不能将问题中提到的球余弦定律距离计算用作主要搜索标准。您需要改用边界框(也就是说,您需要在搜索点的特定距离内搜索点。

    您当前的查询只是通过检查您的地点表中的所有点并按邻近顺序对它们进行排序来找到最接近 (37.77671, -122.3980) 的点。当您使用地理空间时,您正在做一些比这更聪明的事情。您需要建立一个接近限制。我们称其为 10.0 法定英里的半径。请注意,每个纬度有 69.0 法定英里。

    那么你是怎么做到这一切的呢?

    首先为自己制作一个带有几何列的表格,可能是这样的:

    CREATE TABLE geoplace (
      id INT NOT NULL,
      geo GEOMETRY NOT NULL,
      PRIMARY KEY id (id),
      SPATIAL KEY geo (geo)
    ) ENGINE=MYISAM
    

    然后,像这样填充它,将几何 Point 项放入每个 geo 值中。

    INSERT INTO geoplace
    SELECT DISTINCT id,
                    GEOMFROMTEXT(
                      CONCAT('POINT(',
                         lat,
                         ' ',
                         lng,
                    ')')  ) AS geo
     FROM places
    

    显然,您可以将 GEOMETRY 列放入您想要的任何表格中。但是您不能在 InnoDB 表中创建有效的空间索引;该访问方法不支持空间索引。

    然后,您需要这样的查询来检索您的信息。

    SELECT id, X(geo), Y(geo), distance FROM (
    SELECT id, geo,r,
            units * DEGREES( ACOS(
                       COS(RADIANS(latpoint))
                     * COS(RADIANS(X(geo)))
                     * COS(RADIANS(longpoint) - RADIANS(Y(geo)))
                     + SIN(RADIANS(latpoint))
                     * SIN(RADIANS(X(geo))))) AS distance
     FROM geoplace
     JOIN (
            SELECT 37.776708  AS latpoint,  -122.398050 AS longpoint,
                   10.0 AS r, 69.0 AS units
       ) AS p ON (1=1)
     WHERE MbrContains(GeomFromText(
           CONCAT('LINESTRING(',
                  latpoint-(r/units),' ',
                  longpoint-(r /(units* COS(RADIANS(latpoint)))),
                  ',',
                  latpoint+(r/units) ,' ',
                  longpoint+(r /(units * COS(RADIANS(latpoint)))),
                  ')')),  geo)
    ) AS d
     WHERE distance <= r
     ORDER BY distance
    

    请注意,这个巨大的查询使用了您在本子句中提供的参数:

            SELECT 37.776708  AS latpoint,  -122.398050 AS longpoint,
                   10.0 AS r, 69.0 AS units
    

    它将使用MbrContains 进行空间矩形搜索,然后使用球余弦定律公式计算找到的点的距离,然后正确排序。与您开始使用的查询相比,这件事运行得非常快,因为它利用了空间索引。

    这里有更详细的描述。

    http://www.plumislandmedia.net/mysql/using-mysqls-geospatial-extension-location-finder/

    这里有背景。

    http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

    【讨论】:

      猜你喜欢
      • 2017-03-30
      • 2018-04-06
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 2012-02-24
      • 2015-04-23
      • 1970-01-01
      • 2011-06-01
      相关资源
      最近更新 更多