ホームページ > データベース > mysql チュートリアル > 大規模なデータセットに対する距離ベースの検索のために、PHP/MySQL で地理検索クエリを最適化するにはどうすればよいですか?

大規模なデータセットに対する距離ベースの検索のために、PHP/MySQL で地理検索クエリを最適化するにはどうすればよいですか?

DDD
リリース: 2024-11-13 09:42:02
オリジナル
311 人が閲覧しました

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

PHP/MySQL での地理検索 (距離) の最適化

緯度と経度のペアを含む大きなテーブルに対して距離ベースのクエリを実行する場合、クエリのパフォーマンスを最適化することが重要になります。 MySQL クエリが直面する次の課題を考慮してください。

  • MySQL はすべての行を反復処理するため、高い計算コストが発生します。
  • R ツリーのような地理空間拡張機能は複雑な場合があり、数学的な専門知識が必要です。

検索範囲が狭いArea

効率的な解決策は、対象領域の周囲に境界ボックスを定義することです。その後、クエリはこの境界領域内の行を選択できるため、距離計算の数が大幅に削減されます。 Movable Type の記事には、バウンディング ボックスの構築と SQL クエリでの使用に関する詳細なガイドが記載されています。

より正確な結果を得るための Vincenty 式

Haversine 式では不十分な場合正確であれば、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 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート