Intereting Posts
Отправить параметр на сервер из приложения Android модель вызова или просмотр модели вызова? Лучшая практика для организации повторных запросов DBAL в Symfony2? Загрузите файл с App Inventor 2 на сервер через PHP Каков наилучший способ реализации двухстороннего шифрования с помощью PHP? Расширить проверку формы Функция обратного вызова php в классе Обработчик для fastcgi-script возвращает недопустимый код результата Использование php, как вставить текст без перезаписи в начало текстового файла Как я могу отследить этот JSON в этом конкретном выходе? как проверить, сколько видеопотока было просмотрено пользователем с помощью php PHP – SQL – отключить, скрыть или включить кнопку на основе данных Как запустить консольную команду в yii2 из сети разбиение на страницы с использованием кодировки с выбранными записями PHP и MySQL: преобразование сохраненного TIMESTAMP в локальный часовой пояс пользователя

Как ускорить формулу Хаверсина в mysql?

В качестве хобби проекта я начал делать сайт для компании. Я не очень продвинутый в создании сложных кодов для веб-сайта, но я хотел попробовать.

У меня есть база данных почтового индекса из Нидерландов с более чем 471000 записей. Я использую формулу haversine, чтобы посмотреть, какие почтовые индексы находятся в радиусе 13 км, а затем я выбираю каждого пользователя из базы данных, в которой есть почтовый индекс в этом результате. Но для загрузки всех результатов формула занимает 6 секунд. Как я могу ускорить этот процесс?

Код ниже:

$finder = $mysqli->query("SELECT lat, lng FROM postcodetabel WHERE postcode = '$s' OR plaats = '$s'"); $finder1 = mysqli_fetch_assoc($finder); $latitude = $finder1['lat']; $longitude = $finder1['lng']; $query = $mysqli->query("SELECT postcode, ( 6371 * acos ( cos ( radians('$latitude') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('$longitude') ) + sin ( radians('$latitude') ) * sin( radians( lat ) ) ) ) AS distance FROM postcodetabel HAVING distance < 12 ORDER BY distance ASC"); $quertie = $mysqli->query("SELECT bigav, id, naam, email, bedrijfsnaam, telnummer FROM gebruikers WHERE postcode = '$postcode' AND status = 1 AND soort LIKE '%" . $soort . "%'"); while($quertie2 = mysqli_fetch_assoc($quertie)) { echo ' <div class="kapper"> <div class="kapperfoto"><img src="/vluggeknipt/ondernemer/pagina/uploads/'.$quertie2['bigav'].'" style="width:100px;height:100px;"></div> <div class="boektekst"> <font class="headingkap"><strong><a href="?page=profiel&id='.$quertie2['id'].'">Naar profiel &raquo;</a></strong></font><br/> </div> <div class="kappertext"> <font class="headingkap"><a href="?page=profiel&id='.$quertie2['id'].'"><strong>'.$quertie2['naam'].'</strong></a></font><br/> <i class="mobhide">'.$quertie2['email'].' - '.$quertie2['telnummer'].'</i><br/> <i class="mobhide">'.$quertie2['bedrijfsnaam'].'</i> </div></div><br/> '; } 

Заранее спасибо!

Этот запрос никогда не будет особенно быстрым. Однако есть некоторые способы его улучшения.

Во-первых: Формула Хаверсина здесь не нужна. Поправки, которые он применяет, необходимы только тогда, когда кривизна земли является значительным фактором или очень близка к полюсам. Ни один из них здесь не имеет значения – самое большое расстояние, которое нужно точно рассчитать, составляет 12 миль, что едва ли даже за горизонт. В этой шкале Земля эффективно плоская, поэтому теорема Пифагора достаточно хороша для вычисления расстояний.

Одна градус широты составляет около 69 миль, а при 52 ° северной широты (вокруг которой находятся Нидерланды) степень долготы составляет cos(52°) x 69 = 42.5 миль, поэтому формула становится:

 sqrt(pow(69*(lat - $latitude), 2) + pow(42.5*(lng - $longitude), 2)) 

Во-вторых: мы можем использовать «scissor test» для широты и долготы. Если точка больше 12 миль в любом кардинальном направлении от вашей целевой точки, она, конечно же, не может находиться в пределах 12-мильного круга этой точки. Мы можем использовать этот факт для быстрого сравнения по широте и долготе, полностью пропуская расчет расстояния. Используя приведенные выше цифры для одной градуса широты / долготы, мы имеем:

 WHERE (lat BETWEEN ($latitude - 12/69.0) AND ($latitude + 12/69.0)) AND (lng BETWEEN ($longitude - 12/42.5) AND ($longitude + 12/42.5)) 

Обратите внимание, что это не заменяет проверку полного расстояния! Это просто первый шаг, чтобы быстро выбросить точки, которые не могут быть в правильном радиусе. При наличии индекса на lat или lng это позволит серверу базы данных избежать проверки многих строк в базе данных.

почему у вас есть HAVING … из-за того, что ваш запрос не включен в агрегированную функцию, поэтому вы можете фильтровать uing где (но где не использовать, вы должны повторить код) и для использования с использованием, где избежать полного сканирования для результат для оценки

  $query = $mysqli->query("SELECT postcode, ( 6371 * acos ( cos ( radians('$latitude') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('$longitude') ) + sin ( radians('$latitude') ) * sin( radians( lat ) ) ) ) AS distance FROM postcodetabel WHERE 6371 * acos ( cos ( radians('$latitude') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('$longitude') ) + sin ( radians('$latitude') ) * sin( radians( lat ) ) )< 12 ORDER BY distance ASC");