1


3

mysqlクエリの距離計算

数千のエントリのデータベースを照会し、指定されたポイントからの距離でこれを並べる必要があります。

問題は、各エントリに緯度と経度があり、各エントリを取得して距離を計算する必要があることです。 大規模なデータベースでは、各行を取得したくないため、時間がかかる場合があります。

これをmysqlクエリに組み込み、最も近い15エントリのみを取得する必要がある方法はありますか。

E.g.

`SELECT events.id, caclDistance($latlng, events.location) AS distance FROM events ORDER BY distance LIMIT 0,15`

    function caclDistance($old, $new){
       //Calculates the distance between $old and $new
    }

5 Answer


9


オプション1:GeoIPをサポートするデータベースに切り替えて、データベースで計算を行います。

オプション2:次のようなストアドプロシージャを使用して、データベースで計算を実行します。

CREATE FUNCTION calcDistance (latA double, lonA double, latB double, LonB double)
    RETURNS double DETERMINISTIC
BEGIN
    SET @RlatA = radians(latA);
    SET @RlonA = radians(lonA);
    SET @RlatB = radians(latB);
    SET @RlonB = radians(LonB);
    SET @deltaLat = @RlatA - @RlatB;
    SET @deltaLon = @RlonA - @RlonB;
    SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
    COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
    RETURN 2 * ASIN(SQRT(@d)) * 6371.01;
END//

データベースに緯度と経度のインデックスがある場合、PHPで初期境界ボックス($ minLat、$ maxLat、$ minLong、$ maxLong)を計算し、制限することで、計算する必要がある計算の数を減らすことができます。それに基づいたエントリのサブセットへの行($ minLatと$ maxLatの間、および$ minLongと$ maxLongの間の緯度)。 その後、MySQLは行のサブセットに対して距離計算を実行するだけです。

単にストアドプロシージャを使用して距離を計算する場合)、SQLはデータベース内のすべてのレコードを調べ、データベース内のすべてのレコードの距離を計算してから、その行を返すか破棄するかを決定する必要があります。

計算の実行は比較的遅いため、計算する必要がある行のセットを減らして、必要な距離から明らかに外れている行を排除して、高価な計算のみを実行するようにするとよいでしょう。より少ない数の行。

あなたがやっていることは、基本的に地図上に円を描き、最初の点を中心に、距離の半径で描くことであると考えた場合、その後、式は単にその行に含まれる行を識別します…​ ただし、すべての行をチェックする必要があります。

境界ボックスを使用することは、中心点から適切な距離にある左、右、上、および下のエッジで最初にマップ上に正方形を描くようなものです。 次に、そのボックス内に円が描画され、円の最北、最東、最南、および最西のポイントがボックスの境界に接触します。 一部の行はそのボックスの外にあるため、SQLはそれらの行の距離を計算しようとさえしません。 境界ボックス内に収まる行の距離のみを計算して、円内にも収まるかどうかを確認します。

PHP内で($変数名からPHPを実行していると仮定して)、距離に基づいて最小および最大の緯度と経度を算出する非常に簡単な計算を使用し、SQLのWHERE句でそれらの値を設定できますステートメント。 これは事実上私たちのボックスであり、その範囲外にあるものはすべて、実際に距離を計算する必要なく自動的に破棄されます。

Movable Type websiteには(PHPコードを使用した)これに関する適切な説明があります。 GeoPositioningはPHPで機能します。

編集 calcDistanceストアドプロシージャの値6371.01は、返される結果をキロメートル単位で提供する乗数です。 マイル、海里、メートルなどを求める場合は、適切な代替乗数を使用します


5


SELECT events.id FROM events
ORDER BY pow((lat - pointlat),2) + pow((lon - pointlon),2) ASC
 LIMIT 0,15

地球の半径などを使用してメートル単位で絶対距離を計算する必要はありません。

最も近いポイントを取得するには、相対距離で順序付けられたポイントのみが必要です。


0


http://dev.mysql.com/tech-resources/articles/mysql-storedprocedures.html [ストアドプロシージャ]が探しているものだと思います。


0


あなたの質問が「最も近いものを見つける」または「店舗検索」タイプの質問である場合、それらの用語をグーグルで検索できます。 ただし、一般的に、そのタイプのデータには何らかの説明の郵便番号が付随し、郵便番号との関連付けによってリストを絞り込むことができます(Mark Makerが指摘しているように)。

すべてのケースは異なり、これはあなたに当てはまらないかもしれません。