MariaDB最近200个没有半径的地方的距离公式

Distance formula for MariaDB nearest 200 places without radius

我有 MariaDB,服务器版本:10.0.23-MariaDB,带有纬度和经度列(浮点数 10,6)以及根据纬度和经度列计算的 geo_location 列(几何)。

我想找到离一个人最近的200个人。位于中心的人具有传递给查询的纬度和经度。有没有办法在没有半径的情况下做到这一点?所以,如果人口密度高,半径就会小。如果人口密度低,则半径会很大。

大约有400万行,需要越快越好。可以首先根据行所在的县过滤这些行。有的是超大县,人口密度低,有的是小县,人口密度高。我需要找到最近的 200 人的最快方法。

SELECT *, ST_DISTANCE(geo_location, POINT(lon, lat)) AS distance 
FROM geotable 
ORDER by distance DESC
LIMIT 200;

坏消息是它会很慢,因为 st_distance() 没有使用空间索引。您应该尝试通过使用最大半径来限制您的查询 select 更少的记录:

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;

或者如果您有每个国家/地区的 POLYGON 坐标,您可以使用它来代替最大半径。

6 位小数就足够了 (16cm / 0.5 ft),但是 FLOAT (1.7m / 5.6 ft) 失去了一些精度。将 (M,N) 添加到 FLOATDOUBLE 本质上从来都不是一件好事;你招致了 2 次舍入,其中一次是浪费。

在地球上 "find nearest" 没有直接的方法,因为没有“二维”索引。但是,通过对一个维度使用分区,对另一个维度使用集群 PRIMARY KEY,您可以做得很好。

大多数解决方案的真正问题是在找不到有效项的情况下需要命中大量磁盘块。事实上,通常有超过 90% 的行是不需要的。

所有这些都是My lat/lng blog中的'solved'。它可能会触及 800 行以获得您想要的 200 行,并且它们会很好地聚集在一起,因此只需要触及几个块。它不需要 pre-filtering 国家/地区,但它确实需要对 table 进行一些彻底的重组。而且,如果你想区分两个相互拥抱的人,我建议按比例缩放 INT(16 毫米/5/8 英寸)- 度数 * 10000000。此外,FLOAT 不适用于 PARTITIONing; INT 会的。 link 中的代码使用 MEDIUMINT 缩放比例 (2.7m / 8/8 ft),但可以更改。