首页  >  文章  >  数据库  >  如何优化 PHP/MySQL 中的地理搜索查询,以对大型数据集进行基于距离的搜索?

如何优化 PHP/MySQL 中的地理搜索查询,以对大型数据集进行基于距离的搜索?

DDD
DDD原创
2024-11-13 09:42:02221浏览

How can I optimize geo-search queries in PHP/MySQL for distance-based searches on large datasets?

PHP/MySQL 中的地理搜索(距离)优化

在包含经纬度对的大型表上执行基于距离的查询时,优化查询性能变得至关重要。考虑一下 MySQL 查询面临的以下挑战:

  • MySQL 会迭代所有行,从而产生高昂的计算成本。
  • 像 R 树这样的地理空间扩展可能很复杂,并且需要数学专业知识。

限制搜索区域

一个有效的解决方案是在感兴趣的区域周围定义一个边界框。然后,查询可以选择该有界区域内的行,从而显着减少距离计算的数量。 Movable Type 文章提供了有关构建边界框并在 SQL 查询中使用它们的详细指南。

用于更准确结果的 Vincenty 公式

如果半正弦公式不足以精度,可以采用 Vincenty 公式。此 JavaScript 示例演示了计算大圆距离的实现:

//  Vincenty formula to calculate great circle distance between 2 locations expressed as Lat/Long in KM

function VincentyDistance($lat1,$lat2,$lon1,$lon2){
    $a = 6378137 - 21 * sin($lat1);
    $b = 6356752.3142;
    $f = 1/298.257223563;

    $p1_lat = $lat1/57.29577951;
    $p2_lat = $lat2/57.29577951;
    $p1_lon = $lon1/57.29577951;
    $p2_lon = $lon2/57.29577951;

    $L = $p2_lon - $p1_lon;

    $U1 = atan((1-$f) * tan($p1_lat));
    $U2 = atan((1-$f) * tan($p2_lat));

    $sinU1 = sin($U1);
    $cosU1 = cos($U1);
    $sinU2 = sin($U2);
    $cosU2 = cos($U2);

    $lambda = $L;
    $lambdaP = 2*M_PI;
    $iterLimit = 20;

    while(abs($lambda-$lambdaP) > 1e-12 && $iterLimit>0) {
        $sinLambda = sin($lambda);
        $cosLambda = cos($lambda);
        $sinSigma = sqrt(($cosU2*$sinLambda) * ($cosU2*$sinLambda) + ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda) * ($cosU1*$sinU2-$sinU1*$cosU2*$cosLambda));

        //if ($sinSigma==0){return 0;}  // co-incident points
        $cosSigma = $sinU1*$sinU2 + $cosU1*$cosU2*$cosLambda;
        $sigma = atan2($sinSigma, $cosSigma);
        $alpha = asin($cosU1 * $cosU2 * $sinLambda / $sinSigma);
        $cosSqAlpha = cos($alpha) * cos($alpha);
        $cos2SigmaM = $cosSigma - 2*$sinU1*$sinU2/$cosSqAlpha;
        $C = $f/16*$cosSqAlpha*(4+$f*(4-3*$cosSqAlpha));
        $lambdaP = $lambda;
        $lambda = $L + (1-$C) * $f * sin($alpha) * ($sigma + $C*$sinSigma*($cos2SigmaM+$C*$cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)));
    }

    $uSq = $cosSqAlpha*($a*$a-$b*$b)/($b*$b);
    $A = 1 + $uSq/16384*(4096+$uSq*(-768+$uSq*(320-175*$uSq)));
    $B = $uSq/1024 * (256+$uSq*(-128+$uSq*(74-47*$uSq)));

    $deltaSigma = $B*$sinSigma*($cos2SigmaM+$B/4*($cosSigma*(-1+2*$cos2SigmaM*$cos2SigmaM)- $B/6*$cos2SigmaM*(-3+4*$sinSigma*$sinSigma)*(-3+4*$cos2SigmaM*$cos2SigmaM)));

    $s = $b*$A*($sigma-$deltaSigma);
    return $s/1000;
}


echo VincentyDistance($lat1,$lat2,$lon1,$lon2);

结论

通过利用边界框并考虑替代距离计算方法,您可以显着改进MySQL 上的地理搜索查询的性能。无论是大规模搜索还是 Web 应用程序的关键组件,这些优化都将增强用户体验并确保高效的数据库操作。

以上是如何优化 PHP/MySQL 中的地理搜索查询,以对大型数据集进行基于距离的搜索?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn