PHP / SQL使用一条SELECT语句从其他多个lat / lng位置获取所有lat / lng位置

时间:2018-08-22 05:14:45

标签: php mysql

我有两个表:一个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查询即可?

非常感谢, 乔治

1 个答案:

答案 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;
}

?>

请注意我关于多查询的最后评论的重要性,因为这引起了我很大的悲伤。