如何优化 SQL 查询地理定位数据?

How to optimize SQL query geolocating data?

我们的任务是在客户指定的位置找到房产。我们有一个 MySQL table 包含属性的经度和纬度。

地址经纬度

地址 1 42.4001742 -71.1213472

地址 2 42.4651592 -71.01366

因此,从逻辑上讲,我们可以根据客户位置进行 SQL 搜索

Select * from addresses where longitude between (client.location. longitude + 0.1) 
and (client.location. longitude - 0.1) and latitude between 
(client.location. latitude + 0.1) and (client.location. latitude - 0.1)

如果有数千个属性,此搜索的效果如何?优化此搜索的可能方法是什么?

查询有一个范围谓词(where 子句),可以很好地优化索引。可以应用的索引类型很多,但关键是让数据库创建并使用索引来查找您的行,而不是检查 table 中的每一行。如果查询中的谓词匹配索引的所有键,那么在大多数情况下它将用于连接。

因此,您应该在 address table 上有一个包含 longitudelatitude 列的索引。每个数据库的调优方式不同,并且会对不同大小的 table 做出不同的反应,但您的目标是获得一个显示 'index seek' 而没有任何不需要的 'scan' 或 [=20] 的查询计划=] 步骤。索引扫描可以预期 O(log n) 性能,因此它应该随着数据呈指数增长而在线性时间内扩展。

您将需要此索引(使用 BTREE 索引)。

CREATE INDEX latlon ON addresses (latitude, longitude);

您的查询将在纬度(南北方向)上进行索引范围扫描,然后在东西方向上进行过滤。那是相当有效的。

一个纬度(南北)是 69 英里或 111.111 公里(根据拿破仑对米的定义......从赤道到极点一千万)。

每度经度(西-东)的距离因您距赤道的距离而异。离赤道越远,距离越短。在美国马萨诸塞州的萨默维尔,一个经度大约是 51 英里。 (你确实通过你的例子告诉我们你在哪里。)

因此,如果您想要一个以 (42.4002 -71.1213) 为中心的每个方向三英里的边界框,您需要此过滤子句。

WHERE latitude  BETWEEN  42.4002 - (3.0/69.0) 
                    AND  42.4002 + (3.0/69.0)
  AND longitude BETWEEN -71.1213 - (3.0/(69.0 * COS(RADIANS(42.4002))))
                    AND -71.1213 + (3.0/(69.0 * COS(RADIANS(42.4002))))

如果您想以公里为单位提供您的盒子,请使用 111.111 代替 69.0。如果您想要不同大小的盒子,请使用不同的数字代替 3.0。

那个过滤器表达式使用我提到的索引就好了。

如果您 table 中的所有位置主要分布在东西方向而不是南北方向(例如,沿着马萨诸塞州收费公路),则调换两列的顺序在索引中以获得更好的选择性。但通常这并不重要。

CREATE INDEX lonlat ON addresses (longitude, latitude);

您可能会发现它对 read this 有帮助。

专业提示最好举出lat/lon在海洋或玉米田中的例子。