MySQLデータベースに緯度/経度を保存するときに使用する理想的なデータ型は何ですか?
-
03-07-2019 - |
質問
lat / longペアで計算を実行することを念頭に置いて、MySQLデータベースでの使用に最適なデータ型は何ですか?
解決
GISでMySQLの空間拡張を使用します。
他のヒント
Googleは、「Store Locator」の例としてPHP / MySQLソリューションの開始から終了までを提供します。 Googleマップを使用したアプリケーション。この例では、lat / lng値を「Float」として保存します。長さが「10,6」の場合
http://code.google.com/apis/maps/articles/ phpsqlsearch.html
基本的には、場所に必要な精度に依存します。 DOUBLEを使用すると、3.5nmの精度が得られます。 DECIMAL(8,6)/(9,6)は16cmになります。 FLOATは1.7m ...
この非常に興味深い表には、より完全なリストがあります: 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関数のみを厳密に扱っている場合、これで問題ありません。ポリゴン、ライン、またはバッファーポイントを使用して計算を行う必要がある場合、空間演算子は、「関連」を使用しない限り正確な結果を提供しません。オペレーター。 21.5.6 。包含、内部、交差などの関係は、正確なジオメトリ形状ではなくMBRを使用しています(つまり、楕円は長方形のように扱われます)。
また、MySQL Spatialの距離は、最初のジオメトリと同じ単位です。つまり、10進度を使用している場合、距離の測定値は10進度になります。これにより、赤道からフルーターになると正確な結果を得ることが非常に難しくなります。
ARINC424から構築されたナビゲーションデータベースに対してこれを行ったとき、かなりの量のテストを行い、コードを振り返り、DECIMAL(18,12)(実際にはNUMERIC(18,12)を使用しました。 )。
浮動小数点数と倍精度数はそれほど正確ではないため、丸め誤差が発生する可能性があり、これは非常に悪いことです。問題のある実際のデータを見つけたかどうかは思い出せませんが、floatまたはdoubleに正確に格納できないと問題が発生する可能性があることはかなり確信しています
ポイントは、度またはラジアンを使用する場合、値の範囲を知っていることです-そして、小数部分はほとんどの桁を必要とします。
MySQL Spatial Extensions は優れた代替手段です OpenGISジオメトリモデルに従うためです。データベースをポータブルに保つ必要があるため、使用しませんでした。
必要な精度に依存します。
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 の時点で、空間データ型(SDT)、特に POINT
は、単一の座標を格納します。 5.7より前では、SDTはインデックスをサポートしていません(テーブルタイプがMyISAMの場合の5.6を除く)。
注:
-
POINT
クラスを使用する場合、座標を保存するための引数の順序はPOINT(緯度、経度)
でなければなりません。 - 空間インデックスの作成には特別な構文があります。
- SDTを使用する最大の利点は、空間分析関数にアクセスできることです。 、たとえば2点間の距離の計算(
ST_Distance
)、1つのポイントが別のエリアに含まれているかどうかを判断します(ST_Contains
)。
このwiki記事に基づく http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy MySQLの適切なデータ型は、経度と緯度を格納するためのDecimal(9,6)です 個別のフィールド。
緯度(90〜-90度)には DECIMAL(8,6)
を、経度(180〜-180度)には DECIMAL(9,6)
を使用します。ほとんどのアプリケーションでは、小数点以下6桁で十分です。両方とも「署名」する必要があります。負の値を許可します。
遠くに行く必要はありません、Googleマップによると、latとlngの場合はFLOAT(10,6)が最適です。
緯度/経度X 1,000,000をOracleデータベースにNUMBERSとして格納し、倍精度の丸め誤差を回避します。
緯度/経度の小数点第6位までが10 cmの精度であることを考えると、これで十分でした。他の多くのデータベースも、緯度/経度を小数点第6位まで格納します。
まったく異なる視点で:
- マップ、マーカー、ポリゴンなどを表示するためにGoogleに依存している場合は、Googleが計算を行うようにします
- リソースをサーバーに保存し、緯度と経度を単一の文字列(
VARCHAR
)として保存するだけです。例:" -0000.0000001、-0000.000000000000001 " (長さが35で、数字の小数点以下が7桁を超える場合は丸められます); - Googleが数字ごとに7桁以上の10進数を返す場合、将来的に逃亡または微生物;
- 距離マトリックスまたは距離を計算するためのジオメトリライブラリまたは特定のエリアのポイントを検出します。呼び出しは次のように簡単です:
google.maps.geometry.poly.containsLocation(latLng、bermudaTrianglePolygon) )
- 「サーバー側」がたくさんあります;使用できるAPI( Python 、 Ruby on Rails 、 PHP 、 CodeIgniter 、 Laravel 、 Yii 、 Zend Framework など) Google Maps APIを使用しています。
この方法では、数値のインデックス付けや、座標を台無しにする可能性のあるデータ型に関連する他のすべての問題を心配する必要はありません。
アプリケーションによっては、FLOAT(9,6)を使用することをお勧めします
空間キーはより多くの機能を提供しますが、実稼働ベンチマークでは、フロートは空間キーよりもはるかに高速です。 (AVGでは0,01 VS 0,001)
MySQLはすべてのfloatにdoubleを使用します... したがって、double型を使用します。 floatを使用すると、ほとんどの状況で予測不能な丸め値が発生します
すべての操作に最適ではありませんが、マップタイルを作成するか、1つの投影だけで多数のマーカー(ドット)を操作する場合(たとえば、Googleマップなどのメルカトルや他の多くのスリッピーマップフレームワークが期待します)、私は私が「Vast Coordinate System」と呼ぶものを見つけました。本当に便利になります基本的に、xとyピクセル座標を何らかの方法でズームインして保存します。ズームレベル23を使用します。これにはいくつかの利点があります。
- ポイントを処理するたびにではなく、高価な緯度/経度からメルカトルピクセルへの変換を1回行う
- 指定されたズームレベルでレコードからタイル座標を取得するには、1つの右シフトが必要です。
- レコードからピクセル座標を取得するには、1つの右シフトと1つのビット単位のANDが必要です。
- シフトは非常に軽量なので、SQLで行うのが実用的です。つまり、DISTINCTを実行してピクセル位置ごとに1つのレコードのみを返すことができます。これにより、バックエンドから返されるレコード数が削減され、フロントエンドでの処理。
最近のブログ投稿でこれらすべてについて話しました。 http://blog.webfoot.com/2013/03/ 12 / optimizing-map-tile-generation /
いくつかの回答/コメントに非常に驚いた。
誰が自発的に「事前減少」することを望んでいるのでしょうか。精度、その後、より悪い数値で計算を実行しますか?最終的には愚かに聞こえます。
ソースが64ビットの精度を持っている場合、スケールをたとえば次のように自発的に修正するのは確かに愚かなことです。小数点以下6桁、最大9桁の有効桁数に精度を制限します(一般的に提案されている10進数9.6形式で発生します)。
当然、ソース素材の精度でデータを保存します。精度を下げる唯一の理由は、限られたストレージスペースになります。
- 元の精度でソース図を保存する
- ソースから計算された数値を計算の精度で保存します(たとえば、アプリケーションコードがdoubleを使用する場合、結果をdoubleとして保存します)
10進数の9.6形式は、グリッドへのスナップ現象を引き起こします。発生する場合は、それが最後のステップになります。
蓄積されたエラーを巣に招きません。
PostGISの空間関数は、MySQL空間関数の空間関数よりもはるかに機能的です(つまり、BBOX操作に制約されません)。確認してください:リンクテキスト
TL; DR
NASA /軍隊で働いておらず、航空機のナビゲーションシステムを作成していない場合は、FLOAT(8,5)を使用します。
質問に完全に答えるには、いくつかのことを考慮する必要があります:
フォーマット
- 度分秒:40° 26′ 46″ N 79° 58′ 56″ W
- 度の小数分:40° 26.767′ N 79° 58.933′ W
- 小数度1 :40.446° N 79.982° W
- 小数度2 :-32.60875、21.27812
- 他の自家製フォーマットはありますか?独自のホームセントリック座標系を作成して、ホームからの距離と距離として格納することを禁止する人はいません。これは、作業中の特定の問題に意味がある場合があります。
だから答えの最初の部分は-座標を、アプリケーションが使用する形式で保存して、前後の絶え間ない変換を避け、より簡単なSQLクエリを作成することができます。
ほとんどの場合、GoogleマップまたはOSMを使用してデータを表示し、GMapsは「10進度2」を使用しています。フォーマット。そのため、同じ形式で座標を保存する方が簡単になります。
精度
次に、必要な精度を定義します。もちろん、「-32.608697550570334,21.278081997935146」のような座標を保存することはできますが、ポイントまでのナビゲーション中に約ミリメートルを気にかけたことはありますか? NASAで作業しておらず、衛星、ロケット、または飛行機の軌道を行っていない場合は、数メートルの精度で大丈夫です。
一般的に使用される形式は、ドットの後の5桁で、50cmの精度が得られます。
例:X、21.278081 8 とX、21.278081 9 の間には1cmの距離があります。したがって、ドットの後の7桁は1 / 2cmの精度を与え、ドットの後の5桁は1/2メートルの精度を与えます(別個のポイント間の最小距離は1mであるため、丸め誤差はその半分を超えることはできません)。ほとんどの民生用には十分なはずです。
度の小数分形式(40° 26.767′ N 79° 58.933′ W)は、ドットの後の5桁とまったく同じ精度を提供します
省スペースストレージ
10進形式を選択した場合、座標はペア(-32.60875、21.27812)です。明らかに、2 x(符号に1ビット、度に2桁、指数に5桁)で十分です。
だからここで、 Alix Axel をサポートします。FLOAT(10,6)に保存するというGoogleの提案は本当に余分だと言っています。メインに4桁は必要ないからです。一部(符号が分離され、緯度が90に制限され、経度が180に制限されているため)。 FLOAT(8,5)を1 / 2mの精度で、FLOAT(9,6)を50 / 2cmの精度で簡単に使用できます。あるいは、latにはFLOAT(7,5)で十分なので、latとlongを別々の型に格納することもできます。 MySQLのフロートタイプリファレンスをご覧ください。いずれも通常のFLOATに似ており、いずれにしても4バイトになります。
最近は通常、スペースは問題になりませんが、何らかの理由でストレージを本当に最適化する場合(免責事項:事前最適化を行わないでください)、lat(91 000以下の値+符号)+ 2xFLOAT(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
Lat Longの計算には精度が必要なため、数学計算を実行するには、何らかのタイプの10進数型を使用し、格納する数値より少なくとも2高い精度を使用します。私は自分のsqlデータ型については知りませんが、SQLサーバーでは人々はしばしば小数の代わりにfloatまたはrealを使用し、これらは実数ではなく推定数であるため問題になります。したがって、使用するデータ型が浮動小数点型ではなく、真の10進数型であることを確認してください。
A FLOAT
は必要なすべての精度を提供し、各座標を文字列などとして保存するよりも比較関数の方が優れているはずです。
MySQLバージョンが5.0.3より前の場合、特定の浮動小数点比較エラー。
MySQL 5.0.3より前のDECIMALカラムは、文字列として表されるため正確な精度で値を格納しますが、DECIMAL値の計算は浮動小数点演算を使用して行われます。 5.0.3の時点で、MySQLは10進64桁の精度でDECIMAL操作を実行します。これにより、DECIMALカラムに関する最も一般的な不正確な問題が解決されるはずです