PHP / SQL получает все местоположения lat / lng из нескольких других местоположений lat / lng, используя одну инструкцию SELECT

0

У меня две таблицы: таблица карт, содержащая около 3000 пар лат /lng, представляющих реальные "маркерные" местоположения; и таблица "Здания", в которой есть несколько сотен пар лат /lng, также представляющих реальные местоположения зданий. То, что я пытаюсь сделать, - это получить все маркеры, которые видны из всех зданий, при условии, что здания имеют "диапазон видимости", определенный отдельно. У меня есть полностью работающий 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 lat/lng
    $lat = $allBuildings[$i]["lat"];
    $lng = $allBuildings[$i]["lng"];

    // get the building 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 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
    Привет @Arj, я думаю, что одна из вещей, которую ты можешь сделать, чтобы значительно сократить время выполнения, построив запрос один раз внутри цикла for, а затем выполнив его только один раз сразу после for - а также ты думал об использовании PDO? : D Вы можете устранить это пока цикл, а также: D
  • 0
    Привет, Эмма, и спасибо, что нашли время ответить. Когда вы говорите «построить запрос», подразумеваете ли вы объединение и выполнение мультизапроса? Или что-то другое? Кроме того, да, я думал о PDO, но я строю эту функциональность в существующем приложении, используя существующую архитектуру, которая в настоящее время не использует PDO. наверное уже поздно переключаться :)
Показать ещё 4 комментария
Теги:

1 ответ

0

Спасибо emma за это предложение. Вот приведенный выше сценарий, переписанный для перемещения запросов 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 lat/lng
    $lat = $allBuildings[$i]["lat"];
    $lng = $allBuildings[$i]["lng"];

    // get the building 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 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;
}

?>

Обратите внимание на важность моего последнего комментария относительно множественного запроса, поскольку это вызвало у меня много горя.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню