优化 sql 查询以提高效率

Optimizing an sql query for efficiency

我有一个关于地理距离的查询。查询非常快,在我的 224 万行 table 上大约用了 0.1175 秒返回。但是,我只需要最短的距离,使用内置的order by太慢了。

有什么方法可以跟踪 运行ning 最小值并告诉我吗?

例如,如果我有这些结果:

city a - 45km
city b - 48km
city c - 12km 

我可以让它给我 12 公里,记住所有距离值都是计算出来的吗?

这里是排序的查询:

SELECT 
City, 
( 
    6371 * 
    acos(
        cos(radians(-60.61384878636903)) * 
        cos(radians(st_x(location))) * 
        cos(radians(st_y(location)) - 
        radians(112.80061386895574)) + 
        sin(radians(-60.61384878636903)) * 
        sin(radians(st_x(location))))
    ) as distance 
FROM table_name 
HAVING distance <  5 
ORDER BY distance ASC LIMIT 1 

table结构如下:

id - int(12)
location - Point()
City - varchar(255) 

问题在于按标志排序花费的时间太长,无法对数据进行排序并获得最低。它可以只保持 运行ning 最小值,然后在不对性能造成重大影响的情况下给我吗?

table包含,

2227851 - rows
spatial index on location

如果我使用 order by 我得到的 运行 时间大约是 14 秒 如果我不使用 order by 我得到的时间是 .1 秒,这是我想要的 运行或接近

建议:

但如果你不想使用它

  • 预计算常量Set A = cos(radians(-60.61384878636903)) cos 函数非常慢。
  • 过滤您的示例数据。如果您的原点是 X,Y,您可以创建一个正方形 X +- 5, Y +- 5 并在 X,Y
  • 上使用常规索引

不,确实没有办法在查询级别保持 运行 最小值。

基本问题是最小距离对于不同的纬度和经度值是不同的,搜索坐标在查询中作为文字提供。

一个选项是保留 table 以前的搜索坐标,即您之前查找过的坐标,然后使用它来缩短执行另一个查询的需要。首先搜索以前搜索的table,然后从那里得到结果。

当然,如果您向 table_name 添加一行,您可能需要根据新行重新评估保存的搜索坐标,并确定新行的距离是否比什么更短你已经保存了。 (或者只是使整个商店无效,并为您进行的每次搜索重新填充。)


基本问题是必须对 table_name 中的每一行计算 "great-circle distance" 表达式。

对于不同的搜索值,该表达式的结果会有所不同 (纬度和经度)。

无法避免对每一行进行计算,并从所有这些结果中找到最低值。那将是一个 "Using filesort" 操作。使用 LIMIT 1,我们希望 MySQL 不必对整个集合进行排序,它只需通过一次即可确定最小值。

如果您可以限制 table_name 中需要评估的行数,并且可以使用索引有效地排除它们...那将加快查询速度。

限制行数的一种方法是根据搜索纬度和经度定义 "bounding box"。并在 WHERE 子句中指定。并让 MySQL 使用适当的索引。最粗略的边界框可以定义为搜索坐标的 +/-dx 纬度和 +/-dy 经度...例如

 WHERE  t.lat BETWEEN  -60.613848 -4 AND -60.613848 +4 
   AND  t.lon BETWEEN  120.800613 -8 AND 120.800613 +8 

这不是一个理想的边界框,因为经度在赤道的距离比在两极附近的距离要长得多。


至于保持 "running minimum"... 您当前的查询无法完成。如果没有以某种方式键入搜索参数的其他数据存储,则无法完成此操作。