我有MariaDB,服务器版本:10.0.23-MariaDB,纬度和经度列(浮点数10,6)加上从纬度和经度列计算的geo_location列(几何)。
我想从一个人那里找到最近的200人。中心的人具有传递给查询的纬度和经度。没有半径,有没有办法做到这一点?因此,如果人口密度很高,则半径会很小。如果人口密度低,那么半径就会很大。
大约有400万行,它需要尽可能快。可以首先根据它们所在的县来过滤行。有些县超大,人口密度低,有些县是人口密度高的小县。我需要以最快的方式找到最近的200人。
答案 0 :(得分:0)
set @dist = 100;
set @rlon1 = lon-@dist/abs(cos(radians(lat))*69);
set @rlon2 = lon+@dist/abs(cos(radians(lat))*69);
set @rlat1 = lat-(@dist/69);
set @rlat2 = lat+(@dist/69);
SELECT *, ST_DISTANCE(geo_location, POINT(lon, lat)) AS distance
FROM geotable
WHERE ST_WITHIN(geo_location,ENVELOPE(LINESTRING(point(@rlon1, @rlat1), point(@rlon2, @rlat2))))
ORDER by distance DESC
LIMIT 200;
坏消息是它会非常慢,因为st_distance()没有使用空间索引。您应该尝试使用最大半径来限制查询,以选择较少的记录:
$("body").append("<iframe type='content'></iframe>")
或者,如果您拥有每个国家/地区的POLYGON坐标,则可以使用该坐标代替最大半径。
答案 1 :(得分:0)
小数点后6位(16厘米/0.5英尺),但FLOAT
(1.7米/5.6英尺)会失去一些精确度。将(M,N)
添加到FLOAT
或DOUBLE
是绝对不错的。你需要进行2次舍入,其中一次是浪费。
由于没有“二维”索引,因此没有直接在地球上“找到最近”的方法。但是,通过对一个维度使用分区而对另一个维度使用群集PRIMARY KEY
,您可以做得非常好。
大多数解决方案的真正问题是需要在不查找有效项目的情况下点击大量磁盘块。实际上,通常不需要超过90%的触摸行。
所有这些都在My lat/lng blog中得到了解决。它可以触摸大约800行来获得你想要的200行,并且它们将很好地聚集在一起,所以只需要触摸几个块。它不需要对Country进行任何预过滤,但确实需要对表进行一些彻底的重组。而且,如果你想区分两个人相互拥抱,我建议缩放INT
(16毫米/ 5/8英寸) - 度数* 10000000.此外,FLOAT
将不适用于{{1 }}; PARTITIONing
会。该链接中的代码使用INT
缩放(2.7米/ 8/8英尺),但可以更改。