【问题标题】:Whats the fastest way to lookup big tables for points within radius MySQL (latitude longitude)什么是在 MySQL 半径(经纬度)内查找大表的最快方法
【发布时间】:2016-11-27 15:47:00
【问题描述】:

目前我有几张超过 100k 行的表。我正在尝试查找如下数据。

SELECT
*, SQRT(POW(69.1 * (latitude - '49.1044302'), 2) + POW(69.1 * ('-122.801094' - longitude) * COS(latitude / 57.3), 2)) AS distance
FROM stops
HAVING distance < 5
ORDER BY distance limit 100

但目前这种方法在高负载时会变慢。有些查询需要 20 多秒才能完成。

如果有人知道任何更好的优化方法,那就太好了。

【问题讨论】:

标签: mysql sql query-optimization geospatial latitude-longitude


【解决方案1】:

首先,如果你有很多地理空间数据,你应该使用 mysql 的地理空间扩展而不是像这样的计算。然后,您可以create spatial indexes 加速许多查询,而您不必像上面那样编写冗长的查询。

使用与ST_Distance 的比较或创建具有兴趣半径的几何图形以及 ST_within 可能会给您带来良好的结果,并且可能比当前快很多。然而,实现这一目标的最佳和最快方法是,ST_Dwithin 尚未在 mysql 中实现。

【讨论】:

  • 添加空间索引,使用空间函数获取一组粗略匹配并且仍然使用WHERE子句中的当前谓词以及空间分析函数是可行的。优化器会自动知道(它很聪明)使用空间索引在大致正确的区域中找到候选匹配,然后进一步缩小它们,“使用 where”针对非空间谓词过滤匹配行,给出更好的性能,同时保持现有逻辑的精度。空间绝对是前进的道路。
  • 原始查询的公式也可以在存储函数中由内而外重写,该函数计算并返回一个多边形,该多边形表示距目标位置距离 x 的边界框,因为 iirc ST_Distance 不是正弦,它是平面的。
【解决方案2】:

空间索引肯定取决于 MySQL 版本。我们的网站也搜索纬度/经度,但我们使用的是旧版本的 MySQL(5.1-something)(无空间索引)。您的查询与我们的类似,但我们的查询是基于弧度的。根据您的确切需求,您可以(根据您所拥有的)对其进行相当多的优化。

  1. 绝对从数据库查询中删除 sqrt(),它必须为每一行计算 - 仅在最后向用户显示实际距离时计算它 - 还要平方“有距离
  2. 取消引用 lat/lon '49.1044302',使其严格地是一个 int,并在查询之外进行 lat/lon 类型检查。这不会加快速度,但可以防止由于 lat/lon 变量中的虚假尾随空格导致的错误转换。
  3. 将 5 转换为每个方向上的实际纬度/地度差 +/5 以产生限制范围(实际上是一个框)。将它添加到查询的“where”部分——这个限制将使你得到一个大大减少的、几乎精确的结果行集——基本上,lat 和 lon 上的 x 和 y +/- 范围是结果的上限-- 计算的对角线只会稍微改变结果和它们的距离。
  4. 将尽可能多的数学运算移到选择和位置之外——它必须扫描整个表并创建一个临时表,对每一行进行计算,以便为您提供这些结果。查询中的许多数学运算都可以转换为常数。
  5. 通过降低纬度/经度的分辨率(复制)到另一个字段(可能乘以 10 或 100 并转换为 INT)并在该字段上添加索引,进一步加快行缩减(选择框)字段,并在 where 中使用带有 +/- 边界的字段,至少这样它就可以使用一个键 - mysql 可以减少并且这些结果更快。

至少我们是这样做的。

【讨论】:

  • 49.1044302 不是“整数”。 “一个数字”就可以了。此外,在比较数字列时,引号并不重要。
  • 边界框(#3)是这个答案中最有成效的部分——假设你有INDEX(latitude)INDEX(longitude)
  • 不正确的瑞克。虽然“float”不是“int”,但他应该乘以纬度或经度并降低精度以便从数字的、更可取的整数索引中受益的点就在那里。引号也很重要,但不是因为您暗示的原因。如果空格以某种方式使其成为 lat 或 long 变量字符串,则 mysql 优化器不会将“ $var ”转换为数字。通过留下引号,任何错误的空格(可能来自用户输入)将最终在 sql 本身中出现空格,并且变得无害。不要这么快按下“白痴按钮”。
  • 另外,即使你没有关于 lat 和 lon 的 INDEX,在 where 子句中指定范围也会减少 table scan 产生的结果行集,并减少在几何距离上花费的计算.我知道这些观点是正确的,因为尽管您的网站上列出了代码,但我不得不在 mysql 版本 3.23.28 中对大表进行 lan/lot 查询。第一个候选版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 2011-08-04
  • 2017-08-18
  • 1970-01-01
相关资源
最近更新 更多