2017-04-03 56 views
0

作为一个爱好项目,我开始为一家公司制作一个网站。我在制作复杂的网站代码方面并不是很先进,但我想尝试一下。如何加快MySQL中的Haversine公式?

我有一个荷兰邮政编码数据库,其中有超过471000条记录。我使用haversine公式来查找哪些邮政编码位于13 km的半径范围内,然后从数据库中选择每个用户在此结果中具有邮政编码。但公式需要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/> 

    '; } 

在此先感谢!

回答

0

为什么一年比一年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"); 
3

该查询永远不会特别快。但是,有一些方法可以改进。

第一条: Haversine公式在这里没有必要。只有当地球的曲率是一个重要因素,或者非常接近极点时,它才适用的修正。这两者都不是这种情况 - 需要准确计算的最大距离是12英里,这几乎不超过地平线。在这个尺度上,地球是平坦的,所以毕达哥拉斯定理对于计算距离是足够好的。纬度的

一个度为约69英里,在52℃N(周围荷兰在哪里),一个度经度的是cos(52°) x 69 = 42.5英里,所以公式变为:

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

第二:我们可以在纬度和经度上使用“剪刀测试”。如果一个点离目标点的距离超过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)) 

请注意,这并不代替全距离检查!这只是快速抛出不可能在正确范围内的点的第一步。使用latlng上的索引,这将允许数据库服务器避免检查数据库中的许多行。

+0

很好的答案!你可以(/任何人)指出这种方法合理准确的距离上限吗?说,在正确答案的5%以内? – richplane