简体   繁体   English

MySQL中给定半径内的查询点

[英]Query points within a given radius in MySQL

I have created the following MySQL table to store latitude/longitude coordinates along with a name for each point:我创建了以下 MySQL 表来存储纬度/经度坐标以及每个点的名称:

CREATE TABLE `points` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `location` point NOT NULL,
  PRIMARY KEY (`id`),
  SPATIAL KEY `location` (`location`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

I am trying to query:我正在尝试查询:

  • all points within an n mile radius of a given point;给定点的n英里半径内的所有点;
  • the distance of each returned point from the given point每个返回点到给定点的距离

All of the examples I have found refer to using a minimum bounding rectangle (MBR) rather than a radius.我发现的所有示例都涉及使用最小边界矩形 (MBR) 而不是半径。 The table contains approximately 1 million points, so this need needs to be as efficient as possible.该表包含大约 100 万个点,因此需要尽可能高效。

For MySQL 5.7+对于 MySQL 5.7+

Given we have the following simple table,鉴于我们有以下简单的表格,

create table example (
  id bigint not null auto_increment primary key,
  lnglat point not null
);

create spatial index example_lnglat 
    on example (lnglat);

With the following simple data,有了以下简单的数据,

insert into example (lnglat) 
values
(point(-2.990435, 53.409246)),
(point(-2.990037, 53.409471)),
(point(-2.989736, 53.409676)),
(point(-2.989554, 53.409797)),
(point(-2.989350, 53.409906)),
(point(-2.989178, 53.410085)),
(point(-2.988739, 53.410309)),
(point(-2.985874, 53.412656)),
(point(-2.758019, 53.635928));

You would get the points within a given range of another point (note: we have to search inside a polygon) with the following combination of st functions:您将使用以下 st 函数组合获得另一个点的给定范围内的点(注意:我们必须在多边形内搜索):

set @px = -2.990497;
set @py = 53.410943;
set @range = 150; -- meters
set @rangeKm = @range / 1000;

set @search_area = st_makeEnvelope (
  point((@px + @rangeKm / 111), (@py + @rangeKm / 111)),
  point((@px - @rangeKm / 111), (@py - @rangeKm / 111))
);

select id, 
       st_x(lnglat) lng, 
       st_y(lnglat) lat,
       st_distance_sphere(point(@px, @py), lnglat) as distance
  from example
 where st_contains(@search_area, lnglat);

You should see something like this as a result:结果应该是这样的:

3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473

For reference on distance, if we remove the constraint the result for the test point looks like this:对于距离参考,如果我们移除约束,测试点的结果如下所示:

1   -2.990435   53.409246   188.7421181457556
2   -2.990037   53.409471   166.49406509160158
3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473
7   -2.988739   53.410309   136.1875540498202
8   -2.985874   53.412656   360.78532732013963
9   -2.758019   53.635928   29360.27797292756

Note 1 : the field is called lnglat since that's the correct order if you think of points as (x, y) and is also the order most functions (like point) accept the parameter注 1 :该字段称为 lnglat,因为如果您将点视为 (x, y) 则这是正确的顺序,并且也是大多数函数(如点)接受参数的顺序

Note 2 : you can't actually take advantage of spatial indexes if you were to use circles;注意 2 :如果您要使用圆圈,则实际上无法利用空间索引; also note that the point field can be set to accept null but spatial indexes can't index it if it's nullable (all fields in the index are required to be non-null).另请注意,可以将点字段设置为接受空值,但如果它可以为空,则空间索引无法对其进行索引(索引中的所有字段都必须为非空值)。

Note 3 : st_buffer is considered (by the documentation) to be bad for this use case注 3 :st_buffer 被认为(根据文档)对于这个用例是不利的

Note 4 : the functions above (in particular st_distance_sphere) are documented as fast but not necessarily super accurate;注 4 :上述函数(特别是 st_distance_sphere)被记录为快速但不一定超准确; if your data is super sensitive to that add a bit of wiggle room to the search and do some fine tuning to the result set如果您的数据对此非常敏感,则为搜索增加一点回旋余地并对结果集进行一些微调

Thank you both for your answers.谢谢你们的回答。

I eventually found the solution at http://www.movable-type.co.uk/scripts/latlong-db.html .我最终在http://www.movable-type.co.uk/scripts/latlong-db.html找到了解决方案。

Radius is not efficiently indexable. Radius 不能有效地索引。 You should use the bounding rectangle to quickly get the points you are probably looking for, and then filter points outside of the radius.您应该使用边界矩形快速获取您可能正在寻找的点,然后过滤半径之外的点。

I did that for one point inside the circle with radius我在半径的圆内做了一点

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM