如何通过经纬度计算距离来优化SQL查询?

时间:2010-06-22 14:14:10

标签: sql mysql query-optimization

我的表格结构如下:

table name: shop

id_shop      int(10)
name         varchar(200)
latitude     double
longitude    double

我想计算给定坐标与数据库中保存的坐标之间的距离。

我当前的查询:

SELECT *
  FROM `shop` AS `s`
 WHERE
      (
        ( 6371
        * ACOS(
            SIN( RADIANS( latitude ) )
          * SIN( RADIANS( 53.5353010379 ) )
          + COS( RADIANS( latitude ) )
          * COS( RADIANS( 53.5353010379 ) )
          * COS( RADIANS( 14.7984442616 ) - RADIANS( longitude ) )
          )
        )
        <= 25
      )

加上一些数据的JOIN LEFT

有没有办法优化该查询? 使用连接大约需要13毫秒。

我还需要在这里添加一些LIMITCOUNT(*)以获取分页商店的总数。

2 个答案:

答案 0 :(得分:5)

嗯,对于初学者,您可以在存储纬度和经度时将预先计算的内容存储在数据库中。例如,如果您将纬度和经度预先存储为弧度,则只需在存储每个位置时计算RADIANS(纬度)和RADIANS(经度)一次,而不是每次需要进行距离计算时(大概不止一次。)

当你第一次填充行时,也可以通过存储SIN(RADIANS(纬度))和COS(RADIANS(纬度))来减少更多...

我猜你做了很多很多“最接近X”的计算 - 这是人们在面对这个计算时通常会做的事情 - 预先计算你能做什么通常是第一件事尝试。

答案 1 :(得分:5)

以下是一些想法,其中一些可能不适用,具体取决于您的具体情况。

  1. 您可以将纬度和经度转换为弧度,并将其存储在行中。这样可以节省这些计算的成本(实际上,存储数据时会产生一次成本)。
  2. 如果您的表格非常大,您可以使用简单的线性距离计算而不是Haversince公式来限制应用Haversince公式的结果。
  3. 如果您在表格中有其他数据作为良好的第一个过滤器(国家/地区/等),您可以先应用它。
  4. 您可以重新排序您的联接,以便在距离过滤器之后应用它们,这样您就不会因不符合条件的数据而产生联接成本。