オプション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には、これについて(PHPコードを使用して)適切な説明があります。ウェブサイト これは、PHPでGeoPositioningの作業を行うことを計画している人にとっては必読です。
編集 calcDistanceストアドプロシージャの値6371.01は、返される結果をキロメートルで表す乗数です。マイル、海里、メートルなどの結果が必要な場合は、適切な代替乗数を使用してください