优化此查询中的计算?

Optimize calculations in this query?

优化此查询的最佳方法是什么?

$tripsNearLocation = mysqli_query($con, 
   "SELECT * FROM (
       SELECT *
       , ( 3959 * acos( cos(" . $latRad . ") 
         * cos( radians( startingLatitude ) ) 
         * cos( radians( startingLongitude ) 
         - (" . $longRad . ") ) 
         + sin(" . $latRad . ") 
         * sin( radians( startingLatitude ) ) ) ) 
         AS distance FROM trips
      ) as query 
   WHERE distance < 10 
   ORDER BY distance LIMIT 0 , 10;");

50,000 行需要一两秒才能完成。我是否应该添加一个不同的查询来消除所有甚至不在输入坐标的 "close range" 中的行,然后计算剩余的行?假设输入的纬度坐标是 67,则消除纬度坐标不是 65-69 的所有行。

或者添加一个 "state column",如果它们处于不同的状态,它会从计算中删除所有行?

还是只处理这2秒的计算?我担心数据库可能包含超过 100,000 行并且需要很长时间才能执行。

方案 A:对于 100K 行,您可能只需按纬度缩小范围即可。也就是说,

  • 计算对应于“10”个距离单位的纬度
  • 有 INDEX(startingLatitude)
  • 添加到 WHERE 子句以将其限制为 startingLatitude plus/minus“10”。也许你的例子是 AND startingLatitude BETWEEN 65 AND 69.

如果您正在考虑使用 INDEX(lat, lng),那就没那么简单了。看看 Lat 是否足够好。

Plan B:下一个选择将涉及lat和lng,再加上一个子查询。 5.6 版将是有益的。是这样的(包括 INDEX(lat, lng, id) 之后):

SELECT ... FROM (
    SELECT id FROM tbl
        WHERE lat BETWEEN... 
          AND lng BETWEEN... ) x
    JOIN tbl USING (id)
    WHERE ...;

由于种种原因,方案B仅略优于方案A。

计划 C:如果您需要数百万行,则需要 my pizza parlor algorithm。这涉及一个存储过程来反复探测,寻找足够的行。它还涉及 PARTITION 获取粗略的 2D 索引。

方案A和方案B是O(sqrt(N)); C计划是O(1)。也就是说,对于计划 A 和 B,如果将行数增加四倍,则花费的时间也会增加一倍。 Plan C 不会变慢。 (听起来你的代码是 O(N) -- 行数加倍 = 时间加倍。)

这就是我最终解决它的方式,以防将来人们需要参考它。

$tripsNearLocation = mysqli_query($con, "SELECT * FROM (
SELECT *, (3959 * acos(cos(" . $latRad . ") * cos(radians(startingLatitude)) 
* cos(radians(startingLongitude) - (" . $longRad . ")) + sin(" . $latRad . ") 
* sin(radians(startingLatitude)))) AS distance FROM (
SELECT * FROM trips_test WHERE startingLatitude BETWEEN " .
($locationLatitude - 1) . " AND " . ($locationLatitude + 1) . ") as query1) 
as query2 WHERE distance < 10 ORDER BY distance LIMIT 0 , 10;");

虽然我会接受 Rick James 的回答,因为他帮助我找到了这个解决方案。