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() 不使用空间索引。您应该尝试通过使用最大半径来选择较少的记录来限制查询:

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位就足够了(16厘米/0.5英尺),但FLOAT(1.7米/5.6英尺)会失去一些精度。 基本上,将(M,N)粘在FLOATDOUBLE上从来都不是一件好事;您会产生 2 次四舍五入,其中一次是浪费。

地球上"找到最近"的方法并不简单,因为没有"二维"索引。 但是,通过对一个维度使用分区,对另一个维度使用聚簇PRIMARY KEY,您可以做得很好。

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

所有这些都在我的纬度/液化天然气博客中"解决"。 它可能会触及 800 行才能获得您想要的 200 行,并且它们会很好地聚集在一起,因此只需要触摸几个块。 它不需要对国家/地区进行任何预筛选,但确实需要对表格进行一些彻底的重组。 而且,如果你想区分两个互相拥抱的人,我建议使用比例INT(16 毫米/5/8 英寸) - 度 * 10000000。 此外,FLOAT不适用于PARTITIONing; INT会的。 该链接中的代码使用按比例缩放的MEDIUMINT(2.7 米/8/8 英尺),但可以更改。