it-swarm.com.de

Welches ist der ideale Datentyp, wenn Sie Breitengrad/Längengrad in einer MySQL-Datenbank speichern?

Welcher Datentyp eignet sich am besten für die Verwendung mit einer MySQL-Datenbank?

389
Codebeef

Verwenden Sie MySQLs räumliche Erweiterungen mit GIS.

149
Kirk Strauser

Google bietet den Start für die Fertigstellung der PHP/MySQL-Lösung für eine Beispielanwendung "Store Locator" mit Google Maps. In diesem Beispiel speichern sie die lat/lng-Werte als "Float" mit einer Länge von "10,6".

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

142
Ted Avery

Grundsätzlich hängt es von der Präzision ab, die Sie für Ihre Standorte benötigen. Mit DOUBLE haben Sie eine Genauigkeit von 3,5 nm. DECIMAL (8,6)/(9,6) geht auf 16 cm zurück. FLOAT ist 1,7 m ...

Diese sehr interessante Tabelle enthält eine vollständigere Liste: 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

Hoffe das hilft.

110
Simon

Die räumlichen Erweiterungen von MySQL sind die beste Option, da Ihnen eine vollständige Liste der räumlichen Operatoren und Indizes zur Verfügung steht. Mit einem räumlichen Index können Sie sehr schnell entfernungsbasierte Berechnungen durchführen. Bitte beachten Sie, dass die Spatial Extension ab 6.0 noch unvollständig ist. Ich setze MySQL Spatial nicht herunter, sondern lasse Sie nur die Fallstricke wissen, bevor Sie diesbezüglich zu weit gehen.

Wenn Sie streng mit Punkten und nur mit der DISTANCE-Funktion arbeiten, ist dies in Ordnung. Wenn Sie Berechnungen mit Polygonen, Linien oder gepufferten Punkten durchführen müssen, liefern die räumlichen Operatoren keine exakten Ergebnisse, es sei denn, Sie verwenden den Operator "relative". Siehe die Warnung oben in 21.5.6 . Beziehungen wie enthält, innerhalb oder Schnittpunkte verwenden den MBR, nicht die exakte Geometrieform (d. H. Eine Ellipse wird wie ein Rechteck behandelt).

Die Abstände in MySQL Spatial befinden sich in denselben Einheiten wie Ihre erste Geometrie. Das bedeutet, wenn Sie Dezimalgrade verwenden, werden Ihre Abstandsmaße in Dezimalgraden angegeben. Dies macht es sehr schwierig, exakte Ergebnisse zu erhalten, da Sie vom Äquator weitere Informationen erhalten. 

74
James Schek

Als ich dies für eine aus ARINC424 erstellte Navigationsdatenbank tat, habe ich ziemlich viel getestet und auf den Code zurückgesehen. Ich habe ein DECIMAL (18,12) (eigentlich ein NUMERIC (18,12), weil es Firebird war) verwendet.

Floats und Doubles sind nicht so präzise und können zu Rundungsfehlern führen, was sehr schlecht sein kann. Ich kann mich nicht erinnern, ob ich echte Daten gefunden habe, die Probleme hatten - aber ich bin ziemlich sicher, dass die Unfähigkeit, in einem Float oder einem Double genau zu speichern, Probleme verursachen könnte

Der Punkt ist, dass wir bei der Verwendung von Grad oder Bogenmaß den Bereich der Werte kennen - und der gebrochene Teil benötigt die meisten Ziffern.

Die MySQL-Spatial-Erweiterungen sind eine gute Alternative, da sie dem OpenGIS-Geometriemodell folgen. Ich habe sie nicht verwendet, weil ich meine Datenbank portabel halten musste.

69

Kommt auf die Präzision an, die Sie benötigen.

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

Von: http://mysql.rjweb.org/doc.php/latlng

Zusammenfassen:

  • Die genaueste verfügbare Option ist DOUBLE.
  • Der am häufigsten verwendete Typ ist DECIMAL(8,6)/(9,6).

Erwägen Sie ab MySQL 5.7 die Verwendung von Spatial Data Types (SDT), insbesondere POINT zum Speichern einer einzelnen Koordinate. Vor 5.7 unterstützte SDT keine Indizes (mit Ausnahme von 5.6, wenn der Tabellentyp MyISAM ist).

Hinweis:

  • Bei Verwendung der Klasse POINT muss die Reihenfolge der Argumente zum Speichern von Koordinaten POINT(latitude, longitude) sein.
  • Es gibt eine spezielle Syntax für Erstellen eines räumlichen Index .
  • Der größte Vorteil der Verwendung von SDT besteht darin, dass Sie Zugriff auf Funktionen für räumliche Analysen haben, z. Berechnen der Entfernung zwischen zwei Punkten ( ST_Distance ) und Bestimmen, ob ein Punkt in einem anderen Bereich enthalten ist ( ST_Contains ).
36
Gajus

Basierend auf diesem Wiki-Artikel http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy Der geeignete Datentyp in MySQL ist Decimal (9,6) zum Speichern des Längen- und Breitengrades in separate Felder.

32

Verwenden Sie DECIMAL(8,6) für Breitengrad (90 bis -90 Grad) und DECIMAL(9,6) für Längengrad (180 bis -180 Grad). 6 Dezimalstellen sind für die meisten Anwendungen ausreichend. Beide sollten "unterschrieben" sein, um negative Werte zu berücksichtigen.

19
Alex Holsgrove

Keine Notwendigkeit, weit zu gehen, laut Google Maps ist FLOAT (10,6) das beste für lat und lng.

13

Wir speichern Breiten-/Längengrad X 1.000.000 in unserer Oracle-Datenbank als NUMMERN, um Rundungsfehler mit Dopplungen zu vermeiden.

Angesichts der geografischen Breite/Länge bis zur 6. Dezimalstelle war die Genauigkeit von 10 cm alles, was wir brauchten. Viele andere Datenbanken speichern auch lat/long bis zur 6. Dezimalstelle.

7
user18443

In einer völlig anderen und einfacheren Perspektive:

  • wenn Sie sich beim Anzeigen Ihrer Karten, Markierungen, Polygone oder was auch immer auf Google verlassen, lassen Sie die Berechnungen von Google durchführen!
  • sie sparen Ressourcen auf Ihrem Server und speichern Breiten- und Längengrad einfach zusammen als eine einzige Zeichenfolge (VARCHAR). Beispiel: " -0000.0000001, -0000.000000000000001 " (35 Länge und wenn eine Zahl dann mehr als 7 Dezimalstellen hat es wird gerundet);
  • wenn Google mehr als 7 Dezimalstellen pro Zahl zurückgibt, können Sie diese Daten trotzdem in Ihrer Zeichenfolge speichern, nur für den Fall, dass Sie in der Zukunft Flucht oder Mikroben erkennen möchten ;
  • sie können ihre Entfernungsmatrix oder ihre Geometriebibliothek zum Berechnen von Entfernungen verwenden oder Punkte in bestimmten Bereichen ermitteln , wenn die Aufrufe so einfach sind: google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • es gibt viele "serverseitige" APIs, die Sie verwenden können (in Python , Ruby on Rails , PHP , CodeIgniter , Laravel , Yii , Zend Framework usw.), die Google Maps API verwenden.

Auf diese Weise müssen Sie sich keine Sorgen um die Indexierung von Zahlen und all die anderen Probleme machen, die mit Datentypen zusammenhängen, die Ihre Koordinaten beeinträchtigen könnten.

6
Armfoot

Es ist zwar nicht für alle Operationen optimal, aber wenn Sie Kartenkacheln erstellen oder mit einer großen Anzahl von Markern (Punkten) mit nur einer Projektion arbeiten (z. B. Mercator, wie Google Maps und viele andere rutschige Karten-Frameworks), habe ich was gefunden Ich bezeichne "Vast Coordinate System", um wirklich sehr praktisch zu sein. Grundsätzlich speichern Sie die x- und y-Pixelkoordinaten an einem bestimmten Ort - ich verwende die Zoomstufe 23. Dies hat mehrere Vorteile:

  • Sie müssen die teure Lat/lng-zu-Mercator-Pixel-Transformation nicht jedes Mal durchführen, wenn Sie den Punkt bearbeiten
  • Das Abrufen der Kachelkoordinate aus einem Datensatz bei einer Zoomstufe erfordert eine Rechtsverschiebung.
  • Das Abrufen der Pixelkoordinate aus einem Datensatz erfordert eine Rechtsverschiebung und ein bitweises UND.
  • Die Verschiebungen sind so gering, dass es praktisch ist, sie in SQL auszuführen. Dies bedeutet, dass Sie mit DISTINCT nur einen Datensatz pro Pixelposition zurückgeben können, wodurch die Anzahl der vom Backend zurückgegebenen Datensätze reduziert wird, was weniger Verarbeitungsaufwand für die Vorderes Ende. 

Ich habe in einem kürzlich erschienenen Blogbeitrag darüber gesprochen: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

je nach Anwendung empfehle ich die Verwendung von FLOAT (9,6)

mit räumlichen Schlüsseln erhalten Sie mehr Funktionen. In Bezug auf Produktions-Benchmarks sind die Floats jedoch viel schneller als die räumlichen Tasten. (0,01 vs 0,001 in AVG)

4
Torben Brodt

MySQL verwendet double für alle Floats ... Verwenden Sie also den Typ double. Die Verwendung von Float führt in den meisten Situationen zu unvorhersehbaren gerundeten Werten

3
mlinuxgada

Ich bin sehr überrascht von einigen Antworten/Kommentaren.

Warum um alles in der Welt wäre jemand bereit, die Genauigkeit freiwillig vorab zu "verringern" und dann später die schlechteren Zahlen zu berechnen? Klingt letztendlich dumm.

Wenn die Quelle eine 64-Bit-Genauigkeit hat, wäre es sicherlich dumm, die Skala freiwillig auf z. 6 Dezimalstellen, und begrenzen Sie die Genauigkeit auf maximal 9 signifikante Stellen (dies geschieht mit dem üblicherweise vorgeschlagenen 9.6-Dezimalformat).

Natürlich speichert man die Daten mit der Genauigkeit, die das Ausgangsmaterial hat. Der einzige Grund, die Genauigkeit zu verringern, wäre der begrenzte Speicherplatz.

  • Bewahren Sie Quelldaten mit Originalgenauigkeit auf
  • Speichern Sie aus der Quelle berechnete Zahlen in der Genauigkeit, in der die Berechnung erfolgt (z. B. wenn der Anwendungscode Doubles verwendet, speichern Sie die Ergebnisse als Doubles).

Das dezimale 9.6-Format verursacht ein Rastereffekt. Das sollte der allerletzte Schritt sein, wenn es überhaupt passieren soll.

Ich würde keine angesammelten Fehler in mein Nest einladen.

3
Stormwind

Die räumlichen Funktionen in PostGIS sind wesentlich funktionaler (d. H. Nicht auf BBOX-Operationen beschränkt) als die in den räumlichen MySQL-Funktionen. Check it out: Linktext

3
Dylan

TL; DR

Verwenden Sie FLOAT (8,5), wenn Sie nicht in der NASA/Militär arbeiten und keine Navi-Systeme für Flugzeuge herstellen.


Um Ihre Frage vollständig beantworten zu können, müssen Sie einige Punkte beachten:

Format

  • Grad Minuten Sekunden: 40 ° 26 ′ 46 ″ N 79 ° 58 ′ 56 ″ W
  • Grad Dezimalminuten: 40 ° 26.767 'N 79 ° 58.933' W
  • Dezimalgrad 1: 40,446 ° N 79,982 ° W
  • Dezimalgrad 2: -32,60875, 21,27812
  • Ein anderes selbst gemachtes Format? Niemand verbietet Ihnen, Ihr eigenes hauszentriertes Koordinatensystem zu erstellen und als Überschrift und Entfernung von zu Hause aus zu speichern. Dies kann für bestimmte Probleme sinnvoll sein, an denen Sie gerade arbeiten.

Der erste Teil der Antwort wäre also: Sie können die Koordinaten im Format, das Ihre Anwendung verwendet speichern, um ständige Konvertierungen zu vermeiden und einfachere SQL-Abfragen zu erstellen.

Wahrscheinlich verwenden Sie Google Maps oder OSM, um Ihre Daten anzuzeigen, und GMaps verwenden das Format "Dezimalgrad 2". So wird es einfacher, Koordinaten im selben Format zu speichern.

Präzision

Dann möchten Sie die Präzision definieren, die Sie benötigen. Natürlich können Sie Koordinaten wie "-32.608697550570334,21.278081997935146" speichern, aber haben Sie sich beim Navigieren zum Punkt schon einmal um Millimeter gekümmert? Wenn Sie nicht in der NASA arbeiten und keine Satelliten, Raketen oder Flugbahnen durchführen, sollten Sie mit einer Genauigkeit von mehreren Metern zufrieden sein.

Das häufig verwendete Format ist 5-stellig nach Punkten, was eine Genauigkeit von 50 cm ergibt.

Beispiel: Es gibt einen Abstand von 1 cm zwischen X, 21.2780818 und X, 21.2780819. Bei 7 Stellen nach Punkt erhalten Sie eine Genauigkeit von 1/2 cm, und bei 5 Stellen nach Punkt erhalten Sie eine Genauigkeit von 1/2 Metern (da der Mindestabstand zwischen den einzelnen Punkten 1 Meter beträgt und der Rundungsfehler nicht mehr als die Hälfte davon betragen kann). Für die meisten zivilen Zwecke sollte es ausreichen.

grad-Dezimal-Minuten-Format (40 ° 26,767 'N 79 ° 58,933' W) liefert genau die gleiche Genauigkeit wie 5 Stellen nach Punkt 

Platzsparender Speicher

Wenn Sie das Dezimalformat ausgewählt haben, ist Ihre Koordinate ein Paar (-32.60875, 21.27812). Offensichtlich sind 2 x (1 Bit für Vorzeichen, 2 Ziffern für Grad und 5 Ziffern für Exponent) ausreichend. 

Hier möchte ich Alix Axel mit Kommentaren unterstützen, die besagen, dass der Vorschlag von Google, es in FLOAT (10,6) zu speichern, wirklich besonders ist, da Sie für den Hauptteil keine 4 Ziffern benötigen (da das Zeichen getrennt ist und der Breitengrad ist auf 90 und der Längengrad auf 180 begrenzt. Sie können FLOAT (8,5) problemlos für 1/2m Genauigkeit oder FLOAT (9,6) für 50/2cm Genauigkeit verwenden. Sie können auch lat und lat in getrennten Typen speichern, da FLOAT (7,5) für lat ausreicht. Siehe MySQL-Float-Typen reference . Jeder von ihnen ist wie normales FLOAT und entspricht ohnehin 4 Byte.

Normalerweise ist Platz heutzutage kein Thema, aber wenn Sie den Speicher aus irgendeinem Grund wirklich optimieren möchten (Disclaimer: Keine Voroptimierung), können Sie lat (nicht mehr als 91.000 Werte + Vorzeichen) + long (nein) komprimieren mehr als 181 000 Werte + Vorzeichen) bis 21 Bit, dh deutlich weniger als 2xFLOAT (8 Byte == 64 Bit)

2
The Godfather
  1. Die Breiten bewegen sich zwischen -90 und +90 (Grad), daher ist DECIMAL (10, 8) dafür in Ordnung

  2. die Längen reichen von -180 bis +180 (Grad), so dass Sie DECIMAL (11, 8) benötigen.

Hinweis: Die erste Zahl ist die Gesamtzahl der gespeicherten Ziffern und die zweite Zahl ist die Nachkommastelle.

Kurz gesagt: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

0
mahfuz