优化此查询的最佳方法是什么?
$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行,并且需要很长时间才能执行。
答案 0 :(得分:0)
计划A:对于100K行,您可能会因为纬度缩小而逃脱。也就是说,
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的回答,因为他帮我解决了这个问题。