MySQL 5.7 で地理座標間の距離を計算する
MySQL 5.7 で追加された ST_Distance_Sphere 関数を使うと、2 つの地理座標間の大圏距離を自前で実装せずに計算できます。
MySQL 5.7 で追加された ST_Distance_Sphere 関数を使えば、Haversine の公式を自前で実装しなくても、2 つの地理座標間の大圏距離を計算できます。
ST_Distance_Sphere の引数は経度、緯度の順で指定する必要があり、一般的な「緯度、経度」表記とは逆になります。この順序を逆にしてもエラーは発生せず、誤った結果が返されるため注意が必要です。
短距離の例
まずは、大阪市内にある約 2 km 離れた 2 地点間の距離を計算します。
SELECT ST_Distance_Sphere( GeomFromText('POINT(135.507260 34.693946)'), GeomFromText('POINT(135.526201 34.687316)') ) AS distance_meterFROM dual;| row | distance_meter |
|---|---|
| 1 | 1882.1360099034516 |

長距離の例
次に、約 400 km 離れた JR 大阪駅と JR 東京駅を使い、長距離での計算結果を確認します。
SELECT ST_Distance_Sphere( GeomFromText('POINT(135.495951 34.702488)'), -- JR Osaka station GeomFromText('POINT(139.767052 35.681168)') -- JR Tokyo station ) AS distance_meterFROM dual;| row | distance_meter |
|---|---|
| 1 | 403048.2752256764 |

極域に近い例
最後に、北極圏より北に位置するスヴァールバル諸島の 2 地点を使い、高緯度における球面近似の計算結果を確認します。
SELECT ST_Distance_Sphere( GeomFromText('POINT(16.379258 78.655621)'), -- Pyramiden Container Hostel GeomFromText('POINT(16.328528 78.655143)') -- Hotel Tulpan ) AS distance_meterFROM dual;| row | distance_meter |
|---|---|
| 1 | 1110.8932928975748 |

ST_Distance との違い
名前は似ていますが、ST_Distance と ST_Distance_Sphere では空間の扱い方が異なります。MySQL 5.7 の空間計算では、単位が定義されていない無限の平面直交座標系である SRID 0 が前提です。そのため、ST_Distance は 2 つのジオメトリ間の最短距離を、座標と同じ単位の平面距離として返します。
たとえば、経度と緯度を POINT(135.5, 34.7) として格納しても、ST_Distance はそれらを平面上の単純な X 座標と Y 座標として扱います。結果の単位はメートルやキロメートルではなく座標単位です。また、地球の丸みや、極に近づくほど経度 1 度が表す地表上の距離が短くなることも考慮しません。
一方、ST_Distance_Sphere は Point の X と Y を度単位の経度と緯度として解釈し、球面上の最短距離を計算してメートル単位で返します。MySQL 5.7 では、半径を明示しない場合に 6,370,986 メートルの球を使用します。
ST_Distance | ST_Distance_Sphere | |
|---|---|---|
| 座標モデル | 平面直交座標 | 球面 |
| MySQL 5.7 での結果の単位 | 座標単位(SRID 0 の単位は未定義) | メートル |
| 地球の丸み | 考慮しない | 球面近似として考慮する |
| 対応するジオメトリ | 適用可能なジオメトリ型の組み合わせ | Point/Point、Point/MultiPoint の組み合わせ |
| 主な用途 | 平面座標やジオメトリ形状間の距離 | 経度・緯度から地表上のおおよその距離を求める場合 |
経度・緯度から地球上のおおよその物理距離を求める場合は、ST_Distance_Sphere を使います。すでに適切な平面座標へ変換されたデータを扱う場合や、ジオメトリ形状間の最短平面距離を求める場合は、ST_Distance を使います。どちらも道路、鉄道、徒歩などの経路距離を求める関数ではありません。
まとめ
3 つの例から、ST_Distance_Sphere を使って約 2 km と約 400 km の距離に加え、単純な平面近似では誤差が生じやすい北緯 78° 付近の距離も計算できることが分かりました。この関数が球面上の計算を処理するため、2 地点間の距離を求めるだけであれば、アプリケーション側で Haversine の公式を実装したり、別の地理空間ライブラリを導入したりする必要はありません。
ただし、GeomFromText('POINT(...)') では経度を緯度より先に指定します。一般的な緯度・経度の順序に慣れている場合は、引数を取り違えないよう注意してください。
Related posts
Gremlin で Amazon Neptune をクエリする
Amazon Neptune にプロパティグラフを登録し、Gremlin のトラバーサルで関係をクエリする方法を解説します。
複数の Elasticsearch インデックスを横断して検索する
ワイルドカードパターンと明示的なカンマ区切りリストという 2 つの方法で、複数の Elasticsearch インデックスを一度にクエリします。
C4 ダイアグラムでチーム間のコミュニケーションを改善する
C4 モデルの特徴と、UML やインフラ構成図との違いを整理し、相手のロールに合った粒度でソフトウェアアーキテクチャを伝える方法を解説します。
Cognito User Pools と OIDC で Slack サインインを実装する
Cognito user pool を OIDC 経由で Slack と連携させ、"Sign in with Slack" を Amplify で Next.js アプリケーションに組み込みます。
Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする
FastAPI で書いた API バックエンドをコンテナ化し、Lambda Web Adapter と AWS CDK を使って単一の Lambda 関数へデプロイします。
