MySQL地理空间查询 - 返回最近的行

时间:2014-06-11 21:38:19

标签: mysql sql geospatial database-performance

我有一个具有以下结构的表:

id | code | coordinates

ID是主键,代码是我们内部应用程序使用的内容,坐标列是 point 数据类型。

我需要构建一个查询,它会将最近的行快速返回到一组坐标。

例如,如果我给出坐标50.8,-1.3,我希望查询尽可能快地返回最近的行(或者至少比我下面的尝试更快)。

这是我的尝试。我会用它,但返回结果需要0.5秒。

SELECT localities.code
  FROM (
    SELECT glength(LineStringFromWKB( 
            LineString( 
            GeomFromText(astext(coordinates)), 
            GeomFromText(astext( PointFromWKB(POINT(663.422238,10.398996)))))))
      AS distance, code  
FROM locality
) localities
ORDER BY localities.distance ASC
LIMIT 1

任何人都可以使用地理空间扩展构建一个返回结果的查询吗?

1 个答案:

答案 0 :(得分:1)

首先,您的表达式中有一些冗余用于选择距离。

我相信你可以使用

glength(LineString(coordinates,POINT(663.422238,10.398996))) AS distance

而不是你拥有的。这可能对性能有所帮助,但它不会有太多帮助。

构建的查询在locality表上执行全表扫描以计算每个距离。然后按距离对结果进行排序并返回第一个结果。

如果你对所讨论的几何学没有任何先验知识,那么很难做得更好。但是,如果您可以在样本点周围放置一个边界框并将搜索限制在边界框内,那么您可以使用SPATIAL索引来加快速度。

要使用SPATIAL索引,您需要在桌面上使用MyISAM访问方法(InnoDB无法正常工作)。然后在coordinates列上创建索引。

然后你需要找出合适的边界框。我们假设您要排除距候选人POINT(663.422238,10.398996) 50远的任何积分。

您需要做的是:

首先,制作一个几何对象,这条对角线穿过你的边界框,如下所示:

GeomFromText(
   CONCAT('LINESTRING(',
          663.422238 - 50,' ', 10.398996 - 50, ',',
          663.422238 + 50,' ', 10.398996 + 50, ')'))

然后在这样的查询中使用带有SPATIAL-index利用函数MBRContains()(最小边界矩形包含)的几何对象。

SELECT localities.code
  FROM (
     SELECT glength(LineString(coordinates,POINT(663.422238,10.398996))) AS distance,
            code 
       FROM locality
      WHERE  MBRContains(
                GeomFromText(
                       CONCAT('LINESTRING(',
                               663.422238 - 50,' ', 10.398996 - 50, ',',
                               663.422238 + 50,' ', 10.398996 + 50, ')')),
                coordinates )
       ) AS localities
ORDER BY localities.distance ASC
LIMIT 1

关键是边界框。这种运行查询的方式可以通过使用空间索引来选择表中要考虑的非常小的行子集来节省时间。

我在这里详细介绍了lat / long工作。 http://www.plumislandmedia.net/mysql/using-mysqls-geospatial-extension-location-finder/

请注意,获取GeomFromText内容的语法有时候有点繁琐。我希望它是正确的,但我可能放错了逗号或其他东西。