优化此查询中的计算?

时间:2015-03-21 18:37:43

标签: mysql performance optimization query-optimization

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

$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行需要一两秒才能完成。我应该添加一个不同的查询来消除所有甚至不在输入坐标的“近距离”中的行,然后计算剩余的行吗?假设输入的纬度坐标是67,则消除纬度坐标不是65-69的所有行。

或添加“状态列”,如果它们不在同一状态,它会从计算中删除所有行?

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

2 个答案:

答案 0 :(得分:0)

计划A:对于100K行,您可能会因为纬度缩小而逃脱。也就是说,

  • 计算对应于&#34; 10&#34;的纬度。距离单位
  • 拥有INDEX(startingLatitude)
  • 添加到WHERE子句以将其限制为startingLatitude加/减&#34; 10&#34;。也许您的示例是AND startingLatitude BETWEEN 65 AND 69

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

计划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,如果您将行数增加四倍,则会将时间加倍。计划C不会变慢。 (听起来你的代码是O(N) - 行数加倍=时间的两倍。)

答案 1 :(得分:0)

这就是我最终解决它的方式,因为将来人们需要引用它。

$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的回答,因为他帮我解决了这个问题。