MySQLの達人であろうとなかろうと、問題は、さまざまな行を除外する方法を見つけない限り、各ポイントと各都市の間の距離を計算する必要があるということです...
状況を改善する可能性のある2つの一般的なアプローチがあります
- 距離の計算式を簡単にする
- 特定の都市から半径100kまでの可能性の低い候補を除外します
これらの2つの改善方法に入る前に、この100マイルの距離に関して必要な精度のレベルを決定する必要があります。また、データベースでカバーされている地理的領域を示す必要があります(これは米国大陸などです。
この理由は、数値的にはより正確ですが、大円の式は非常に計算コストがかかるためです。パフォーマンスを向上させるもう1つの方法は、ある種の「グリッド座標」をLat / Long座標に追加して(またはその代わりに)保存することです。
編集 :
より単純な(ただし正確性は低い)式に関するいくつかのアイデア :
私たちは比較的短い距離を扱っているので(そして私は北緯30度から48度の間だと推測しています)、ではなくユークリッド距離(またはより良いのはユークリッド距離の2乗)を使用できますより複雑な球面三角法の公式。
期待される精度のレベルによっては、経度全体の直線距離に対して1つのパラメータを設定し、考慮される領域全体で平均値をとることも許容される場合があります(たとえば、約46 法令 マイル)。すると、数式は次のようになります
LatDegInMi = 69.0
LongDegInMi = 46.0
DistSquared = ((Lat1 - Lat2) * LatDegInMi) ^2 + ((Long1 - Long2) * LongDegInMi) ^2
行数を制限するためにフィルタリングするグリッド情報を含む列のアイデアについて 距離の計算で考慮されます。
システム内の各「ポイント」には、都市であれ、別のポイント(配達場所、店舗場所など)であれ、25マイルの2乗を定義する2つの整数座標が割り当てられます。 *ポイントが存在する25マイル。基準点(特定の都市)から100マイル以内の任意の点の座標は、最大でx方向に+/- 4、y方向に+/-4になります。次に、次のようなクエリを記述できます
SELECT city, state, latitude, longitude, COUNT(*)
FROM zipcodes Z
JOIN points P
ON P.GridX IN (
SELECT GridX - 4, GridX - 3, GridX - 2, GridX - 1, GridX, GridX +1, GridX + 2 GridX + 3, GridX +4
FROM zipcode ZX WHERE Z.id = ZX.id)
AND
P.GridY IN (
SELECT GridY - 4, GridY - 3, GridY - 2, GridY - 1, GridY, GridY +1, GridY + 2 GridY + 3, GridY +4
FROM zipcode ZY WHERE Z.id = ZY.id)
WHERE P.Status = A
AND ((Z.latitude - P.latitude) * LatDegInMi) ^2
+ ((Z.longitude - P.longitude) * LongDegInMi) ^2 < (100^2)
GROUP BY city,state,latitude,longitude;
LongDegInMiは、ハードコードされているか(米国大陸内のすべての場所で同じ)、または郵便番号テーブルの対応するレコードから取得されている可能性があることに注意してください。同様に、LatDegInMiはハードコーディングすることができます(他のLatDegInMiとは異なり、比較的一定であるため、変更する必要はほとんどありません)。
これが高速である理由は、郵便番号テーブルとポイントテーブルの間のデカルト積のほとんどのレコードについて、距離をまったく計算しないためです。インデックス値(GridXおよびGridY)に基づいてそれらを削除します。
これにより、どのSQLインデックスを生成するかという問題が発生します。確かに、次のことが必要になる場合があります。-GridX + GridY +ステータス(ポイントテーブル上)-GridY + GridX +ステータス(おそらく)-都市+州+緯度+経度+ GridX +GridY(郵便番号テーブル上)
グリッドの代わりに、特定の都市の緯度と経度に基づいて、検討する緯度と経度の制限を「制限」することもできます。つまり、JOIN条件はINではなく範囲になります:
JOIN points P
ON P.latitude > (Z.Latitude - (100 / LatDegInMi))
AND P.latitude < (Z.Latitude + (100 / LatDegInMi))
AND P.longitude > (Z.longitude - (100 / LongDegInMi))
AND P.longitude < (Z.longitude + (100 / LongDegInMi))