緯度/経度のペアで計算を実行することになりますが、MySQLデータベースでの使用に最適なデータ型は何ですか?
GISでMySQLの 空間拡張 を使用してください。
グーグルはグーグルマップを使った "Store Locator"アプリケーションの例としてPHP/MySQLの解決策を提供します。この例では、緯度/経度の値を長さ "10,6"の "Float"として格納します。
基本的にそれはあなたがあなたの場所に必要な精度に依存します。 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
お役に立てれば。
MySQLのSpatial Extensionsは、あなたが自由に使える空間演算子とインデックスの完全なリストを持っているので、最良の選択肢です。空間インデックスを使用すると、距離に基づく計算をすばやく実行できます。 6.0以降、Spatial Extensionはまだ不完全です。私はMySQL Spatialを落としているのではありません。これを理解し過ぎる前に落とし穴を知らせるだけです。
あなたがポイントとDISTANCE機能だけを厳密に扱っているならば、これは大丈夫です。 Polygons、Lines、またはBuffered-Pointsを使用して計算を実行する必要がある場合は、 "related"演算子を使用しない限り、空間演算子は正確な結果を提供しません。 21.5.6 の先頭にある警告を参照してください。包含、包含、交差などの関係は、正確なジオメトリ形状ではなく、MBRを使用しています(つまり、楕円は長方形のように扱われます)。
また、MySQL Spatialの距離は最初のジオメトリと同じ単位です。つまり、10進数を使用している場合は、距離の測定値は10進数で表示されます。あなたが赤道からさらに遠くなるにつれて、これは正確な結果を得ることを非常に難しくするでしょう。
ARINC424から構築されたナビゲーションデータベースに対してこれを行ったとき、私はかなりの量のテストをしてコードを振り返って、DECIMAL(18,12)を使いました。
浮動小数点数や倍精度数はそれほど正確ではなく、丸め誤差が生じる可能性がありますが、これは非常に悪いことです。問題のある実際のデータを見つけたかどうかを思い出すことはできません - しかし、floatまたはdoubleに正確に格納できないことが問題を引き起こす可能性があることはほぼ確実です。
重要なのは、度またはラジアンを使用するときに、値の範囲がわかっていること、そして小数部分には最大桁数が必要なことです。
MySQL Spatial Extensions は、 OpenGIS Geometry Model に従っているため、優れた選択肢です。 )私は自分のデータベースをポータブルにしておく必要があったので、私はそれらを使いませんでした。
あなたが要求する精度によります。
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)
である必要があります。ST_Distance
)、1点が別の領域内に含まれるかどうかを判断する( ST_Contains
)。このウィキの記事 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy に基づくと、MySQLの適切なデータ型はDecimal(9,6)です。 )経度と緯度を別々のフィールドに保存するため。
緯度(90から-90度)にはDECIMAL(8,6)
を使用し、経度(180から-180度)にはDECIMAL(9,6)
を使用します。ほとんどのアプリケーションでは小数点以下6桁で問題ありません。両方とも、負の値を考慮に入れるために「署名」されるべきです。
グーグルマップによると、遠くに行く必要はない、と最高の緯度と経度のためのFLOAT(10,6)です。
倍精度の丸め誤差を避けるために、緯度/経度X 1,000,000をOracleデータベースにNUMBERSとして格納します。
小数位6桁までの緯度/経度が10 cmの精度であるとすれば、それは私たちが必要としていたすべてのことでした。他の多くのデータベースでも、緯度/経度を小数点第6位まで格納しています。
完全に異なる単純な視点で:
VARCHAR
)として一緒に保存するだけです。例: " -0000.0000001、-0000.000000000000001 "(35の長さと数字の場合7桁を超える10進数がある場合、丸められます);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
これにより、数値のインデックス付けや、座標を台無しにする可能性のあるデータ型に関連する他のすべての問題を心配する必要がなくなります。
すべての操作に最適というわけではありませんが、地図のタイルを作成したり、1つの投影法で多数のマーカー(ドット)を操作したりする場合(Googleマップや他の多くのスリップマップフレームワークが期待するMercatorなど)私は「広大な座標系」を本当に便利にするために呼びます。基本的には、xとyのピクセル座標をズームインして保存します - 私はズームレベル23を使用します。これにはいくつかの利点があります。
私は最近のブログ記事でこれらすべてについて話しました: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
あなたのアプリケーションに応じて、私はFLOAT(9,6)を使用することをお勧めします
空間キーはより多くの機能を提供しますが、生産ベンチマークではフロートは空間キーよりはるかに高速です。 (AVGで0,01 VS 0,001)
MySQLはすべての浮動小数点数に対してdoubleを使用します...そのため、double型を使用します。 floatを使用すると、ほとんどの場合予測不能な丸められた値になります。
私はいくつかの答え/コメントに非常に驚いています。
一体誰が自発的に精度を「前もって減少させ」、そして後でもっと悪い数で計算を実行しても構わないと思っているのでしょうか。結局愚かに聞こえます。
ソースが64ビットの精度を持っているなら、確かに自主的にスケールを例えばに修正することは愚かなことでしょう。小数点以下6桁まで、精度を最大9桁の有効桁数に制限します(これは、一般的に提案されている10進数9.6形式で起こります)。
当然のことながら、ソース素材が持っている精度でデータを保存します。精度を低下させる唯一の理由は、記憶スペースが限られていることです。
10進数の9.6フォーマットは、snap-to-grid現象を引き起こします。もしそれが起こるのであれば、それが一番最後のステップであるべきです。
私は私の巣に積み重ねられた誤りを招くつもりはありません。
PostGISの空間関数は、MySQLの空間関数よりもはるかに機能的です(つまり、BBOX操作に制限されません)。チェックしてみてください。 リンクテキスト
TL; DR
あなたがNASA /軍隊で働いていなくて、航空機をナビシステムにしていないならば、FLOAT(8,5)を使用してください。
あなたの質問に完全に答えるためには、いくつかのことを考慮する必要があります。
フォーマット
そのため、答えの最初の部分は次のようになります。アプリケーションが使用する形式で座標を格納して、前後に一定の変換が行われないようにして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以上の値+符号)
緯度は-90〜+ 90(度)の範囲です。そのため、DECIMAL(10、8)で構いません。
経度の範囲は-180〜+ 180(度)なので、DECIMAL(11、8)が必要です。
注:最初の数字は保存されている桁数の合計です。2番目の数字は小数点以下の桁数です。
一言で言えば:lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL