web-dev-qa-db-ja.com

MySQLデータベースに緯度/経度を格納するときに使用するのに理想的なデータ型は何ですか?

緯度/経度のペアで計算を実行することになりますが、MySQLデータベースでの使用に最適なデータ型は何ですか?

406
Codebeef

GISでMySQLの 空間拡張 を使用してください。

156
Kirk Strauser

グーグルはグーグルマップを使った "Store Locator"アプリケーションの例としてPHP/MySQLの解決策を提供します。この例では、緯度/経度の値を長さ "10,6"の "Float"として格納します。

http://code.google.com/apis/maps/articles/phpsqlsearch.html

146
Ted Avery

基本的にそれはあなたがあなたの場所に必要な精度に依存します。 DOUBLEを使用すると、3.5nmの精度が得られます。 DECIMAL(8,6)/(9,6)は16cmになります。フロートは1.7メートルです...

この非常に興味深いテーブルはより完全なリストを持っています: http://mysql.rjweb.org/doc.php/latlng

Datatype               Bytes            Resolution

Deg*100 (SMALLINT)     4      1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5      1570 m    1.0 mi  Cities
SMALLINT scaled        4       682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6        16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7        16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6       2.7 m    8.8 ft
FLOAT                  8       1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9        16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8        16mm    5/8 in  Marbles
DOUBLE                16       3.5nm     ...    Fleas on a dog

お役に立てれば。

115
Simon

MySQLのSpatial Extensionsは、あなたが自由に使える空間演算子とインデックスの完全なリストを持っているので、最良の選択肢です。空間インデックスを使用すると、距離に基づく計算をすばやく実行できます。 6.0以降、Spatial Extensionはまだ不完全です。私はMySQL Spatialを落としているのではありません。これを理解し過ぎる前に落とし穴を知らせるだけです。

あなたがポイントとDISTANCE機能だけを厳密に扱っているならば、これは大丈夫です。 Polygons、Lines、またはBuffered-Pointsを使用して計算を実行する必要がある場合は、 "related"演算子を使用しない限り、空間演算子は正確な結果を提供しません。 21.5.6 の先頭にある警告を参照してください。包含、包含、交差などの関係は、正確なジオメトリ形状ではなく、MBRを使用しています(つまり、楕円は長方形のように扱われます)。

また、MySQL Spatialの距離は最初のジオメトリと同じ単位です。つまり、10進数を使用している場合は、距離の測定値は10進数で表示されます。あなたが赤道からさらに遠くなるにつれて、これは正確な結果を得ることを非常に難しくするでしょう。

74
James Schek

ARINC424から構築されたナビゲーションデータベースに対してこれを行ったとき、私はかなりの量のテストをしてコードを振り返って、DECIMAL(18,12)を使いました。

浮動小数点数や倍精度数はそれほど正確ではなく、丸め誤差が生じる可能性がありますが、これは非常に悪いことです。問題のある実際のデータを見つけたかどうかを思い出すことはできません - しかし、floatまたはdoubleに正確に格納できないことが問題を引き起こす可能性があることはほぼ確実です。

重要なのは、度またはラジアンを使用するときに、値の範囲がわかっていること、そして小数部分には最大桁数が必要なことです。

MySQL Spatial Extensions は、 OpenGIS Geometry Model に従っているため、優れた選択肢です。 )私は自分のデータベースをポータブルにしておく必要があったので、私はそれらを使いませんでした。

70

あなたが要求する精度によります。

Datatype           Bytes       resolution
------------------ -----  --------------------------------
Deg*100 (SMALLINT)     4  1570 m    1.0 mi  Cities
DECIMAL(4,2)/(5,2)     5  1570 m    1.0 mi  Cities
SMALLINT scaled        4   682 m    0.4 mi  Cities
Deg*10000 (MEDIUMINT)  6    16 m     52 ft  Houses/Businesses
DECIMAL(6,4)/(7,4)     7    16 m     52 ft  Houses/Businesses
MEDIUMINT scaled       6   2.7 m    8.8 ft
FLOAT                  8   1.7 m    5.6 ft
DECIMAL(8,6)/(9,6)     9    16cm    1/2 ft  Friends in a mall
Deg*10000000 (INT)     8    16mm    5/8 in  Marbles
DOUBLE                16   3.5nm     ...    Fleas on a dog

投稿者: http://mysql.rjweb.org/doc.php/latlng

要約すると:

  • 最も正確に利用可能なオプションはDOUBLEです。
  • 使用される最も一般的な見られる型はDECIMAL(8,6)/(9,6)です。

MySQL 5.7 以降、 Spatial Data Types (SDT)、具体的には POINT の使用を検討してください。単一座標を格納します。 5.7より前のSDTはインデックスをサポートしていません(テーブルタイプがMyISAMの場合は5.6を除きます)。

注意:

  • POINTクラスを使用する場合、座標を格納するための引数の順序はPOINT(latitude, longitude)である必要があります。
  • 空間インデックス を作成するための特別な構文があります。
  • SDTを使用する最大の利点は、 Spatial Analyses Functions にアクセスできることです。 2点間の距離を計算し( ST_Distance )、1点が別の領域内に含まれるかどうかを判断する( ST_Contains )。
37
Gajus

このウィキの記事 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy に基づくと、MySQLの適切なデータ型はDecimal(9,6)です。 )経度と緯度を別々のフィールドに保存するため。

32

緯度(90から-90度)にはDECIMAL(8,6)を使用し、経度(180から-180度)にはDECIMAL(9,6)を使用します。ほとんどのアプリケーションでは小数点以下6桁で問題ありません。両方とも、負の値を考慮に入れるために「署名」されるべきです。

19
Alex Holsgrove

グーグルマップによると、遠くに行く必要はない、と最高の緯度と経度のためのFLOAT(10,6)です。

13

倍精度の丸め誤差を避けるために、緯度/経度X 1,000,000をOracleデータベースにNUMBERSとして格納します。

小数位6桁までの緯度/経度が10 cmの精度であるとすれば、それは私たちが必要としていたすべてのことでした。他の多くのデータベースでも、緯度/経度を小数点第6位まで格納しています。

7
user18443

完全に異なる単純な視点で:

  • マップ、マーカー、ポリゴンなどを表示するためにGoogleに依存している場合は、Googleが計算を実行できるようにします。
  • サーバーにリソースを保存し、緯度と経度を単一の文字列(VARCHAR)として一緒に保存するだけです。例: " -0000.0000001、-0000.000000000000001 "(35の長さと数字の場合7桁を超える10進数がある場合、丸められます);
  • googleが数字ごとに7桁以上の10進数を返す場合、一部の 将来の逃亡者または微生物 ;を検出する場合に備えて、とにかくそのデータを文字列に格納できます。
  • 距離行列 または ジオメトリライブラリ を使用して距離を計算するか、 特定の領域のポイントを検出する を次のような単純な呼び出しで使用できます:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • 使用できる「サーバーサイド」APIがたくさんあります( PythonRuby on RailsPHPCodeIgniterLaravelYiiZend Framework など)Google Maps APIを使用します。

これにより、数値のインデックス付けや、座標を台無しにする可能性のあるデータ型に関連する他のすべての問題を心配する必要がなくなります。

6
Armfoot

すべての操作に最適というわけではありませんが、地図のタイルを作成したり、1つの投影法で多数のマーカー(ドット)を操作したりする場合(Googleマップや他の多くのスリップマップフレームワークが期待するMercatorなど)私は「広大な座標系」を本当に便利にするために呼びます。基本的には、xとyのピクセル座標をズームインして保存します - 私はズームレベル23を使用します。これにはいくつかの利点があります。

  • ポイントを処理するたびにではなく、高価なlat/lngからmercatorへのピクセル変換を1回実行します。
  • ズームレベルを指定してレコードからタイル座標を取得するには、1つ右シフトします。
  • レコードからピクセル座標を取得するには、1回の右シフトと1回のビット単位のANDが必要です。
  • シフトは非常に軽量なのでSQLで行うのが実用的です。つまり、ピクセル位置ごとに1つのレコードのみを返すようにDISTINCTを実行できるため、バックエンドから返されるレコード数が削減されます。フロントエンド。

私は最近のブログ記事でこれらすべてについて話しました: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

あなたのアプリケーションに応じて、私はFLOAT(9,6)を使用することをお勧めします

空間キーはより多くの機能を提供しますが、生産ベンチマークではフロートは空間キーよりはるかに高速です。 (AVGで0,01 VS 0,001)

4
Torben Brodt

MySQLはすべての浮動小数点数に対してdoubleを使用します...そのため、double型を使用します。 floatを使用すると、ほとんどの場合予測不能な丸められた値になります。

4
mlinuxgada

私はいくつかの答え/コメントに非常に驚いています。

一体誰が自発的に精度を「前もって減少させ」、そして後でもっと悪い数で計算を実行しても構わないと思っているのでしょうか。結局愚かに聞こえます。

ソースが64ビットの精度を持っているなら、確かに自主的にスケールを例えばに修正することは愚かなことでしょう。小数点以下6桁まで、精度を最大9桁の有効桁数に制限します(これは、一般的に提案されている10進数9.6形式で起こります)。

当然のことながら、ソース素材が持っている精度でデータを保存します。精度を低下させる唯一の理由は、記憶スペースが限られていることです。

  • 元の精度で元の数値を保存する
  • 計算が行われる精度でソースから計算された数値を格納します(例えば、アプリケーションコードが倍精度を使用する場合、結果を倍精度として格納します)。

10進数の9.6フォーマットは、snap-to-grid現象を引き起こします。もしそれが起こるのであれば、それが一番最後のステップであるべきです。

私は私の巣に積み重ねられた誤りを招くつもりはありません。

4
Stormwind

PostGISの空間関数は、MySQLの空間関数よりもはるかに機能的です(つまり、BBOX操作に制限されません)。チェックしてみてください。 リンクテキスト

3
Dylan

TL; DR

あなたがNASA /軍隊で働いていなくて、航空機をナビシステムにしていないならば、FLOAT(8,5)を使用してください。


あなたの質問に完全に答えるためには、いくつかのことを考慮する必要があります。

フォーマット

  • 度分秒秒:40°26 '46″ N 79°58″ 56″ W
  • 度小数分:40°26.767 'N 79°58.933' W
  • 10進数1:40.446°N 79.982°W
  • 10進数2:-32.60875、21.27812
  • 他の自家製フォーマットは?誰もあなた自身の家を中心とした座標系を作ることを禁じ、あなたの家からの方位と距離としてそれを保存します。これはあなたが取り組んでいるいくつかの特定の問題にとって意味があるかもしれません。

そのため、答えの最初の部分は次のようになります。アプリケーションが使用する形式で座標を格納して、前後に一定の変換が行われないようにしてSQLクエリを簡単にすることができます。

たぶんあなたはあなたのデータを表示するのにGoogleマップかOSMを使っています、そしてGMapは "decimal degree 2"フォーマットを使っています。そのため、座標を同じ形式で格納する方が簡単です。

精度

次に、必要な精度を定義します。もちろん、 " - 32.608697550570334,21.278081997935146"のような座標を格納することができますが、ポイントまでのナビゲーション中にミリメートルについて気にすることはありますか?あなたがNASAで働いていなくて、衛星やロケットや飛行機の軌道をしていないのであれば、あなたは数メートルの精度で大丈夫なはずです。

一般的に使用されるフォーマットはドットの後の5桁で、これは50cmの精度を与えます。

:Xと21.2780818とXとの間に1cmの距離があります。21.2780819 。つまり、ドットの後の7桁が1/2cmの精度、ドットの後の5桁が1/2メートルの精度になります(異なる点間の最小距離は1mなので、丸め誤差はその半分以下になることはありません)。ほとんどの市民目的のためにそれは十分であるべきです。

度分数形式(40°26.767 'N 79°58.933' W)は、ドットの後の5桁とまったく同じ精度を提供します。

スペース節約ストレージ

小数点形式を選択した場合は、座標はペアになります(-32.60875、21.27812)。明らかに、2 x(符号は1ビット、度数は2桁、指数部は5桁)で十分です。

だからここで私はあなたが4桁を必要としないので、FLOAT(10,6)にそれを格納するためのGoogleの提案は本当に余分だというコメントからAlix Axelをサポートしたいと思います主要部分の場合(符号が分離され、緯度は90に制限され、経度は180に制限されているため)。 1/2mの精度の場合はFLOAT(8,5)、50/2cmの精度の場合はFLOAT(9,6)を簡単に使用できます。 FLOAT(7,5)で十分なので、latとlongを別々の型で格納することもできます。 MySQLのfloat型 リファレンス を参照してください。それらのどれもが普通のFLOATのようで、とにかく4バイトに等しいでしょう。

通常はスペースは問題になりませんが、何らかの理由で本当にストレージを最適化したい場合(免責事項:事前最適化はしないでください)、lat(91 000以下の値+符号)+ long(no 2 = FLOAT(8バイト== 64ビット)より大幅に少ない21ビットまでの181 000以上の値+符号)

2
The Godfather
  1. 緯度は-90〜+ 90(度)の範囲です。そのため、DECIMAL(10、8)で構いません。

  2. 経度の範囲は-180〜+ 180(度)なので、DECIMAL(11、8)が必要です。

注:最初の数字は保存されている桁数の合計です。2番目の数字は小数点以下の桁数です。

一言で言えば:lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

1
mahfuz