我有两个表:一个Map表,它具有约3,000个经纬度对,代表真实的“标记”位置;还有一个包含几百个经/纬度对的Buildings表,它们也代表了现实中的建筑物位置。我要尝试做的是获得所有建筑物都可见的所有标记,假设建筑物的“视线范围”是分别定义的。我有一个可以正常运行的可以正常运行的PHP脚本:
<?php
// query the Buildings table to get the building data we need
$sql = "SELECT type, lat, lng FROM Buildings;";
$result = mysqli_query($conn, $sql);
while ($row = mysqli_fetch_assoc($result)) {
$allBuildings[] = $row;
}
$result -> close();
// count how many buildings there are to save time in the loop
$buildingsNumber = count($allBuildings);
// this is the key query, which runs a SELECT query for every building so that only the markers visible by the buildings are shown
for ($i = 0; $i < $buildingsNumber; $i++) {
// get the building's lat/lng
$lat = $allBuildings[$i]["lat"];
$lng = $allBuildings[$i]["lng"];
// get the building's vision range in metres
$distance = $buildings[$allBuildings[$i]["type"]]["vision_range"];
// this is the core query. it is a radius search using lat/lngs with the centre being the building's location and the radius being its vision_range
$sql = "SELECT Map.lat, Map.lng,
(6378137 * acos(cos(radians($lat)) * cos(radians(lat)) * cos(radians(lng) - radians($lng)) + sin(radians($lat)) * sin(radians(lat))))
AS distance FROM Map
HAVING distance < $distance;";
while ($row = mysqli_fetch_assoc($result)) {
$markersArray[] = $row;
}
}
?>
问题是,对于许多单个查询,结果在大约20-30秒内返回。这是有道理的,因为从我的PHP服务器到MySQL服务器的往返似乎需要30毫秒。我需要一个几乎立即返回结果的查询,因此理想情况下,我想避免这些多次往返并发送一个返回一组结果的查询。
我以前曾尝试在不同的查询中使用mysqli_multi_query,但是我从未使它成功运行。我也正在考虑串联查询,但是我不确定这也行不通。有没有人成功能够做类似的事情?还是有人可以建议一种方法来重写我的脚本,而该脚本只需要运行一个SELECT查询即可?
非常感谢, 乔治
答案 0 :(得分:0)
感谢艾玛的建议。这是上面的脚本,重写后将SELECT查询移到for循环之外,并将多查询用于结果:
<?php
// query the Buildings table to get the building data we need
$sql = "SELECT type, lat, lng FROM Buildings;";
$result = mysqli_query($conn, $sql);
while ($row = mysqli_fetch_assoc($result)) {
$allBuildings[] = $row;
}
$result -> close();
// count how many buildings there are to save time in the loop
$buildingsNumber = count($allBuildings);
// this is the key query, which runs a SELECT query for every building so that only the markers visible by the buildings are shown
for ($i = 0; $i < $buildingsNumber; $i++) {
// get the building's lat/lng
$lat = $allBuildings[$i]["lat"];
$lng = $allBuildings[$i]["lng"];
// get the building's vision range in metres
$distance = $buildings[$allBuildings[$i]["type"]]["vision_range"];
// this is the core query. it is a radius search using lat/lngs with the centre being the building's location and the radius being its vision_range
$sql .= "SELECT Map.lat, Map.lng,
(6378137 * acos(cos(radians($lat)) * cos(radians(lat)) * cos(radians(lng) - radians($lng)) + sin(radians($lat)) * sin(radians(lat))))
AS distance FROM Map
HAVING distance < $distance;";
}
// note two important things: multi query doesn't work without the MYSQLI_USE_RESULT flag, and we don't close a multi query result otherwise we get server errors
$result = mysqli_multi_query($conn, $sql, MYSQLI_USE_RESULT);
while ($row = mysqli_fetch_assoc($result)) {
$markersArray[] = $row;
}
?>
请注意我关于多查询的最后评论的重要性,因为这引起了我很大的悲伤。