如何在MySQL中使用地理空间“点”字段查询表

时间:2014-03-07 00:17:59

标签: mysql sql geolocation geospatial

我有一个“places”表,其中包含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

如何更改此选项以使用表格中的“point”字段而不是lat / lng

1 个答案:

答案 0 :(得分:2)

使用MySQL地理空间扩展进行此类操作需要做一些事情。

  1. 您必须使用MyISAM表作为地理空间数据。
  2. 您的表中需要有GEOMETRY列,且必须为NOT NULL。
  3. 您不能将问题中提到的球面 - 余弦 - 法律距离计算用作主要搜索条件。您需要使用边界框(也就是说,您需要在搜索点的特定距离内搜索点。
  4. 您当前的查询只是通过检查位置表中的所有点并按邻近顺序对它们进行排序,找到最近的点(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/