Voici ma solution complète mise en œuvre en PHP.
Cette solution utilise la formule de Haversine telle que présentée dans http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL .
Il convient de noter que la formule Haversine présente des faiblesses autour des pôles. Cette réponse montre comment mettre en œuvre le formule de distance du Grand Cercle de vincenty pour contourner ce problème, mais j'ai choisi de n'utiliser que la Haversine car elle est suffisamment bonne pour mes besoins.
Je stocke la latitude en tant que DECIMAL(10,8) et la longitude en tant que DECIMAL(11,8). J'espère que cela vous aidera !
showClosest.php
<?PHP
/**
* Use the Haversine Formula to display the 100 closest matches to $origLat, $origLon
* Only search the MySQL table $tableName for matches within a 10 mile ($dist) radius.
*/
include("./assets/db/db.php"); // Include database connection function
$db = new database(); // Initiate a new MySQL connection
$tableName = "db.table";
$origLat = 42.1365;
$origLon = -71.7559;
$dist = 10; // This is the maximum distance (in miles) away from $origLat, $origLon in which to search
$query = "SELECT name, latitude, longitude, 3956 * 2 *
ASIN(SQRT( POWER(SIN(($origLat - abs(latitude))*pi()/180/2),2)
+COS($origLat*pi()/180 )*COS(abs(latitude)*pi()/180)
*POWER(SIN(($origLon-longitude)*pi()/180/2),2)))
as distance FROM $tableName WHERE
longitude between ($origLon-$dist/abs(cos(radians($origLat))*69))
and ($origLon+$dist/abs(cos(radians($origLat))*69))
and latitude between ($origLat-($dist/69))
and ($origLat+($dist/69))
having distance < $dist ORDER BY distance limit 100;";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
echo $row['name']." > ".$row['distance']."<BR>";
}
mysql_close($db);
?>
./assets/db/db.php
<?PHP
/**
* Class to initiate a new MySQL connection based on $dbInfo settings found in dbSettings.php
*
* @example $db = new database(); // Initiate a new database connection
* @example mysql_close($db); // close the connection
*/
class database{
protected $databaseLink;
function __construct(){
include "dbSettings.php";
$this->database = $dbInfo['host'];
$this->mysql_user = $dbInfo['user'];
$this->mysql_pass = $dbInfo['pass'];
$this->openConnection();
return $this->get_link();
}
function openConnection(){
$this->databaseLink = mysql_connect($this->database, $this->mysql_user, $this->mysql_pass);
}
function get_link(){
return $this->databaseLink;
}
}
?>
./assets/db/dbSettings.php
<?php
$dbInfo = array(
'host' => "localhost",
'user' => "root",
'pass' => "password"
);
?>
Il est possible d'améliorer les performances en utilisant une procédure stockée MySQL, comme le suggère l'article "Geo-Distance-Search-with-MySQL" publié ci-dessus.
J'ai une base de données de ~17 000 places et le temps d'exécution des requêtes est de 0,054 seconde.
1 votes
Il s'agit d'une sorte de duplication de la Recherche de proximité question.
1 votes
Il y a une série de diapositives par Alexander Rubin sur Recherche géo (de proximité) avec MySQL (lien PDF)
0 votes
Méfiez-vous des réponses ici. La plupart d'entre elles ne peuvent pas utiliser d'index et sont donc peu performantes pour les grands ensembles de données. Certaines sont limitées au calcul de la distance non sphérique, et ne sont donc pas utiles dans de nombreuses applications globales.
0 votes
Discussion plus approfondie, notamment sur la mise à l'échelle, la précision et les 5 techniques concurrentes : mysql.rjweb.org/doc.php/find_nearest_in_mysql
0 votes
Si la requête dit
HAVING distance < ...
alors la requête est susceptible de vérifier chaque ligne et de calculer la distance pour chacune d'entre elles. (Lent et non évolutif).