В качестве хобби проекта я начал делать сайт для компании. Я не очень продвинутый в создании сложных кодов для веб-сайта, но я хотел попробовать.
У меня есть база данных почтового индекса из Нидерландов с более чем 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 »</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");